Skip to content

Status NeoPixel blinks green (ALL_DONE) instead of red after code.py raises an exception — return-code mismatch in main.c (10.x regression) #11287

Description

@gallaugher

CircuitPython version and board name

Adafruit CircuitPython 10.2.1 on <date>; Adafruit Circuit Playground Bluefruit with nRF52840

Code/REPL

print("You Are Awesome!)   # missing closing quote → SyntaxError

Behavior

After the code ends with an uncaught exception (SyntaxError or NameError — the traceback prints correctly to the serial console), the status NeoPixel blinks GREEN once every 5 seconds — the "code finished without error" pattern.

Expected, per the Learn guide troubleshooting page and docs (https://learn.adafruit.com/welcome-to-circuitpython/troubleshooting): "2 RED blinks: Code ended due to an exception."

The red exception blink never appears for any exception I can produce. Additionally, the serial status bar / terminal title shows "Done" after an exception rather than the line@file ExceptionName form.

Description

This looks like a return-code scheme mismatch introduced when the MicroPython v1.25-era shared/runtime/pyexec.c (new exit-code scheme) was merged, while main.c still tests the old flag value:

main.c line 588 (tag 10.2.1; line ~579 on main — still present):

if (_exec_result.return_code != PYEXEC_EXCEPTION) {
    ...
    color = ALL_DONE; ...
} else {
    color = EXCEPTION;
    blink_count = EXCEPTION_BLINKS;
}

shared/runtime/pyexec.h (10.2.1): PYEXEC_EXCEPTION is the old bit flag (0x200), but the new scheme defines PYEXEC_UNHANDLED_EXCEPTION as (1) (with MICROPY_PYEXEC_ENABLE_EXIT_CODE_HANDLING) or (0) (without).

shared/runtime/pyexec.c (10.2.1), parse_compile_execute: on an uncaught exception it sets ret = PYEXEC_UNHANDLED_EXCEPTION; (line 233) and stores it via result->return_code = ret; (line 244). Nothing in pyexec.c ever returns 0x200 anymore, so return_code != PYEXEC_EXCEPTION is always true and the red EXCEPTION branch in main.c is unreachable — every exception shows the green ALL_DONE blink.

The same stale test appears at main.c line 272 (10.2.1) in supervisor_execution_status():

c
} else if ((_exec_result.return_code & PYEXEC_EXCEPTION) != 0 && ...

which is why the status bar reports "Done" after an exception.

For contrast, on the 9.2.x branch shared/runtime/pyexec.c line 204 still set ret = PYEXEC_EXCEPTION;, so the red blink worked there — this is a 10.x regression.

Additional information

Nearby code in main.c (e.g. the _exec_result.return_code == 0 success test around line 549) already uses the new scheme, so the fix is presumably to update the two remaining old-scheme tests to check PYEXEC_UNHANDLED_EXCEPTION / nonzero-and-not-special-flag as appropriate.
Thanks for your work!!!

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugregressionThings that used to work but don't any longer

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions