Skip to content

Fix KeyError crash when 3MF metadata comes back empty (addresses #78) - #98

Open
qoncept96 wants to merge 1 commit into
drndos:mainfrom
qoncept96:fix/keyerror-empty-3mf-metadata
Open

qoncept96 wants to merge 1 commit into
drndos:mainfrom
qoncept96:fix/keyerror-empty-3mf-metadata

Conversation

@qoncept96

Copy link
Copy Markdown

Problem

getMetaDataFrom3mf() returns {} on every failure path (RequestException,
BadZipFile, ParseError, bare Exception — tools_3mf.py:293-323). Both callers
then immediately hard-index it:

# mqtt_bambulab.py:266  (cloud / project_file path)
print_id = insert_print(PRINTER_STATE["print"]["subtask_name"], "cloud", PENDING_PRINT_METADATA["image"])

# mqtt_bambulab.py:316  (local path)
print_id = insert_print(PENDING_PRINT_METADATA["file"], PRINTER_STATE["print"]["print_type"], PENDING_PRINT_METADATA["image"])

So any transient FTP/network hiccup, or a 3MF the parser doesn't like, turns into
KeyError: 'image' or KeyError: 'file' inside the MQTT callback.

This is the crash in #78 ("When print starts from printer - openspoolman throws
errors", KeyError: 'file'). It's also the root of the reports where print history
silently stops populating: the exception escapes mid-way through building
PENDING_PRINT_METADATA, leaving the module global half-initialised.

Note the if PENDING_PRINT_METADATA: guard added at :310 does not help — by the
time it runs, {} has already had print_type/task_id/subtask_id written onto
it, so it is truthy but still missing file and image.

The downstream ["complete"] cascade from this was already fixed in #76; this is
the same class of bug at the two sites that actually raise first.

Fix

.get() at both call sites. insert_print() already stores these straight into
nullable columns, so None is fine and the print is still recorded — just without
a thumbnail/filename — instead of taking down MQTT handling.

-      print_id = insert_print(PRINTER_STATE["print"]["subtask_name"], "cloud", PENDING_PRINT_METADATA["image"])
+      print_id = insert_print(PRINTER_STATE["print"]["subtask_name"], "cloud", PENDING_PRINT_METADATA.get("image"))
-            print_id = insert_print(PENDING_PRINT_METADATA["file"], PRINTER_STATE["print"]["print_type"], PENDING_PRINT_METADATA["image"])
+            print_id = insert_print(PENDING_PRINT_METADATA.get("file"), PRINTER_STATE["print"]["print_type"], PENDING_PRINT_METADATA.get("image"))

Testing

These guards have been running in production on a LAN-mode P1S since 2026-08 (on
0.3.0, rebased onto main and redeployed 2026-09-03). I hit the 'image'
variant originally as a repeating crash: the exception escaped mid-way through
building PENDING_PRINT_METADATA, and every subsequent MQTT message then died
until the container was restarted, so tracking went silently dead.

I have not written an automated repro for either call site — the change is a
narrow .get() on two values that insert_print() already accepts as NULL. The
'file' traceback in #78 is a reporter's, not mine.

getMetaDataFrom3mf() returns {} on every failure path, but both callers
immediately hard-index it, so a failed or unparseable 3MF raises
KeyError: 'image' (cloud path) or KeyError: 'file' (local path) inside
the MQTT callback instead of just recording a print without a thumbnail.

The local-path crash is issue drndos#78. The `if PENDING_PRINT_METADATA:`
guard above it does not help, because by then {} has had print_type,
task_id and subtask_id written onto it and is truthy.

insert_print() stores both values in nullable columns, so .get() keeps
the print recorded and leaves MQTT handling alive.

Addresses drndos#78
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant