Circuit errors
A wiring mistake raises CircuitError, and circuit.py reports it with its traceback under the editor. This page lists every message the library can raise, grouped by where the mistake is, with the fix for each.
The board
| Message | Cause and fix |
|---|---|
a board has one Raspberry Pi: create Pi() once and reuse it | A second Pi() in the same circuit. Create the board once, keep it in pi, and use that variable everywhere (The Pi and its pins). |
unknown Pi model 'x'; choose one of pi4b, pi5, pi-zero-2w | The model string is not one of the three board slugs. Use Pi(), Pi("pi4b"), Pi("pi5") or Pi("pi-zero-2w"). |
GPIO28 is not on the header; use GPIO0–GPIO27 | pi.GPIO28 and above, or pi.gpio(99). Only GPIO0–GPIO27 are on the header; pick a number in that range. |
physical pins are numbered 1–40 | pi.pin(0) or pi.pin(41). Physical pin numbers run from 1 to 40. |
there is no Raspberry Pi: add pi = Pi() to circuit.py | circuit.py never created a board. Every circuit starts with pi = Pi() before it buys any part. |
Pi(pi) has no pin 'nonsense'; pins: P1, P2, … P40, CSI | pi.pin("nonsense") — a board pin name that does not exist. Use GPIO0–GPIO27, a rail name, a bus name, or a physical number. |
Wires
| Message | Cause and fix |
|---|---|
<part> has more than two pins: wire one of its pins, e.g. part.dc_plus | A chain (>>) or connect() reached a part that has no two chain ends — a relay, a keypad or another many-pin part. Wire the pin you mean instead: pi.GPIO17 >> relay.in_. |
<pin> is wired to itself | pi.GPIO17 >> pi.GPIO17, or connect(pin, pin). Wire two different pins (Wires and chains). |
<module> has no chain: call self.chain(near, far) in build() | >> was used on a module (module >> …) that never called chain(). Call self.chain("near", "far") in build(), or skip the chain and wire one of its exposed pins (Modules). |
can only wire pins together, got X and Y | Something that is not a pin reached the wire builder. >>, connect() and the returned chain ends always pass pins, so ordinary circuit code never sees this; if it appears, a custom ends or expose() value is not a Pin. |
Parts and settings
| Message | Cause and fix |
|---|---|
there is no part "x"; see the shop for slugs | Part("x") with a slug that is not in the catalogue. Check the slug (run shop() to print the catalogue) or use the part's class instead (Buying and naming parts). |
"x" is not a part in the shop | A Component subclass with TYPE set to something the catalogue does not have. Set TYPE to a shop slug, or subclass Module for your own parts. |
Button() takes settings by name: none / Resistor() takes settings by name: ohms | A positional argument was given to a part that has no main setting, or more than one positional argument was given. Pass settings by name: Resistor(ohms=330). |
Resistor has no setting 'colours'; settings: ohms | An unknown constructor keyword. Use one of the settings the message lists — the part's page shows them too. |
LED color must be one of red, yellow, green, blue, white, not 'purple' | An enum setting outside its options. Use one of the listed values. |
Resistor ohms must be a number, not 'abc' | A number setting was given text (or True/False), often by quoting it. Pass a number: Resistor(330). |
Resistor ohms must be between 1 and 10000000, not 0 | A number setting outside its range. Pick a value between the two bounds. |
at= takes a grid position (x, y) in whole cells, e.g. at=(80, 10) | at= was not a pair of whole numbers. Use at=(x, y) with two integers. |
Modules
| Message | Cause and fix |
|---|---|
TwoLEDs.build() created no parts | The module's build() ran without creating any shop part. Create at least one part inside build() (Modules). |
expose(sig=…) needs a pin, got 17 | self.expose() was given something that is not a Pin. Expose a part's pin: self.expose(sig=self.r.pin1). |
TwoLEDs(lights) exposes no pin 'sig3'; pins: sig1, sig2, gnd | A name was looked up that expose() never published. Use one of the names the message lists, or publish it in build(). |
Not every mistake is a CircuitError
Two related mistakes report a different exception, so their message looks different in the editor:
- An attribute that is not a pin raises
AttributeError, notCircuitError:led.v_pluson an LED saysLED(led) has no pin or attribute 'v_plus'; pins: a, k, and a module says similar with its exposed names. Useled.pin("A")or check the attribute spelling on Pin naming. - A module without
build()raisesNotImplementedError:TwoLEDs must define build(self) to create its parts.
Electrical mistakes: warnings, then damage
circuit.py can build a circuit that is wired legally but would hurt a real Pi. Those show up while it runs, over the board and in the warnings, not as a CircuitError:
| What happens | What you see |
|---|---|
| A GPIO sources or sinks more than 16 mA | A warning: "GPIO17 (pin 11) is sourcing 24 mA — keep it under 16 mA." The pin keeps working. |
| More than 50 mA, or more than 3.6 V on a GPIO | The same warning plus a countdown: "It will be damaged if this lasts 0.5 s." The wires on that pin are marked in amber. |
| …and it lasts 0.5 s | The pin is damaged: "GPIO17 (pin 11) is damaged: 66 mA through it for 0.5 s." Its wires turn red, the message also goes in the console, and the pin stops working: it no longer drives anything, reads 0, and ignores your program. |
A damaged pin stays damaged for the rest of the run, and the message stays on the board after Stop so you can read what happened. Fix the wiring (usually a missing resistor, or a 5 V signal that needs a divider) and press Run: every run starts with a new Pi. In a contest or practice task, a damaged pin also fails the "Nothing is damaged or overloaded" test.
The 3V3 rail's 50 mA budget and two supplies wired together (a short) only warn for now.
Going deeper
- The messages come from the library's own checks (
CircuitErroris the sole exception type the wiring library raises for wiring mistakes), so they name the actual part, pin or setting involved rather than a line number. - Read the
e.g.suggestion. When a part has no chain ends, the message names the first pin's attribute (part.dc_plusfor the relay); when a setting is wrong, it lists the settings that exist. CircuitErroris imported with the rest:from wiring import CircuitErrorif you want to catch it in your own helper code — for example to try a wiring and fall back without stopping the build.