jet and blow_out are not LiquidHandler parameters. They are collected by **backend_kwargs and forwarded to STARBackend.aspirate, which declares them by name.
STARBackend.aspirate has 42 named parameters beyond ops and use_channels:
import inspectfrom pylabrobot.liquid_handling.backends.hamilton.STAR_backend import STARBackendparams = [p for p in inspect.signature(STARBackend.aspirate).parametersif p notin ("self", "ops", "use_channels")]print(len(params), "vendor parameters")print(params[:8])
The argument is dropped, not passed on — the operation still runs.
3
Under STRICT the same call raises instead.
4
Strictness is a module-level global, so it stays changed until set back.
default strictness: Strictness.WARN
WARN -> Extra arguments to backend.aspirate: {'not_a_real_option'}
STRICT-> Extra arguments to backend.aspirate: {'not_a_real_option'}
Strictness
Extra argument on a backend without **kwargs
IGNORE
logged at debug, dropped
WARN (default)
UserWarning, dropped
STRICT
TypeError
WarningGotcha: STRICT does nothing on the chatterbox
The generic chatterbox declares **backend_kwargs on every operation, so _check_args returns before the strictness branch is ever reached. Setting Strictness.STRICT and passing not_a_real_option=True to a chatterbox-backed handler raises nothing:
STARChatterboxBackend subclasses STARBackend, so it inherits the real signatures and the real argument checking, and overrides only the parts that would talk to a machine.
The same rack the chatterbox recipes throughout this book pick up from without complaint.
2026-08-27 22:14:10,987 - pylabrobot - WARNING - Resource 'ot_rack' is very high on the deck: 279.19 mm. Be careful when traversing the deck.
RuntimeError: Cannot pick up tips on channels [0].
Import path.
STARChatterboxBackend is not re-exported from pylabrobot.liquid_handling.backends. Import it from pylabrobot.liquid_handling.backends.hamilton.STAR_chatterbox. Its constructor takes the machine’s configuration — num_channels, core96_head_installed, iswap_installed, and the MachineConfiguration / ExtendedConfiguration dataclasses — which is how you model a specific instrument rather than a generic one.
See also:opentrons_chatterbox.py provides the same thing for the OT-2.
14.4 Jog a channel by hand
Move one channel to a coordinate, outside any pipetting operation.
The message is empty, so the traceback’s last line is the only clue about which call failed.
repr: NotImplementedError() | message: ''
14.5 Read a backend error family
Read which module failed from a Hamilton firmware error.
from pylabrobot.liquid_handling.backends.hamilton.STAR_backend import ( STARFirmwareError, STARModuleError, ClotDetectedError,)module_error = ClotDetectedError( message="Clot detected", trace_information=61, raw_response="C0RTid0001er99", raw_module="C0",)firmware_error = STARFirmwareError( errors={"Pipetting channel 1": module_error}, raw_response="C0RTid0001er99/61",)for module, err in firmware_error.errors.items():print(f"{module}: {type(err).__name__}")print(f" message: {err.message}")print(f" trace: {err.trace_information}")print(f" raw module:{err.raw_module}")print("is a STARModuleError:", isinstance(module_error, STARModuleError))
1
Constructed here; on hardware star_firmware_string_to_error builds these by parsing the firmware response string.
2
STARFirmwareError wraps a dict keyed by module name, one entry per module that reported a fault.
3
Same consumption pattern as ChannelizedError (chapter 10): iterate the dict, read each cause.
Pipetting channel 1: ClotDetectedError
message: Clot detected
trace: 61
raw module:C0
is a STARModuleError: True
The shape repeats across vendors.
TecanError, VantageFirmwareError, the Cytomat and Liconic families, and the Molecular Devices errors follow the same layout: one base class per vendor, leaf classes per documented fault. Catch the base; read the leaf.
See also: the portable errors that raise identically on every backend are in chapter 10.
14.6 What to remember
Unrecognised keyword arguments to lh.aspirate and friends are forwarded to the backend. STARBackend.aspirate names 42 of them.
_check_args returns immediately if the backend method declares **kwargs. The generic chatterbox does, so no strictness level validates anything against it.
Strictness is a module-level global: IGNORE drops, WARN warns and drops, STRICT raises. Missing required arguments raise regardless.
STARChatterboxBackend subclasses STARBackend, so it validates kwargs and tip types like a STAR with no machine attached. Import it from its module; it is not re-exported.
prepare_for_manual_channel_operation then move_channel_x/y/z jogs one channel; NotImplementedError on the generic chatterbox.
STARFirmwareError.errors is keyed by module name; each value is a STARModuleError subclass with message, trace_information, raw_response, and raw_module.