Skip to content

Commit 307d8cc

Browse files
committed
Tighten XEUS status-field guard and extend to cleanup cell
e.args tuple comparison survives any upstream change to KeyError message formatting, which str(e) equality would silently miss. The cell source in the synthetic traceback field was redundant with the rendered output — the source is already shown next to the error block — and inflated error output for large cells. Traceback entries are conventionally stack frames, not source dumps. The kernel-deps cleanup_cell execute_cell call has the same exposure: any XEUS-based Python kernel (e.g. xeus-python) would hit it via cleanup.py. Guarded symmetrically but non-fatally, since cleanup failures shouldn't abort the render.
1 parent 331ddd6 commit 307d8cc

2 files changed

Lines changed: 20 additions & 5 deletions

File tree

news/changelog-1.10.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ All changes included in 1.10:
4848

4949
- ([#14297](https://github.com/quarto-dev/quarto-cli/pull/14297)): Fix `quarto.utils.is_empty_node()` returning inverted results for text nodes (`Str`, `Code`, `RawInline`).
5050

51+
## Engines
52+
53+
### Jupyter
54+
55+
- ([#14374](https://github.com/quarto-dev/quarto-cli/pull/14374)): Avoid a crash when a XEUS-based kernel (e.g. Maple 2025) returns `execute_reply` without the required `status` field. The failing cell is recorded as an error instead of aborting the render. (author: @ChrisJefferson)
56+
5157
## Other fixes and improvements
5258

5359
- ([#6651](https://github.com/quarto-dev/quarto-cli/issues/6651)): Fix dart-sass compilation failing in enterprise environments where `.bat` files are blocked by group policy.

src/resources/jupyter/notebook.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -380,9 +380,18 @@ def handle_meta_object(obj):
380380
if cleanup_cell:
381381
kernel_supports_daemonization = True
382382
nb.cells.append(cleanup_cell)
383-
client.execute_cell(
384-
cell=cleanup_cell, cell_index=len(client.nb.cells) - 1, store_history=False
385-
)
383+
try:
384+
client.execute_cell(
385+
cell=cleanup_cell, cell_index=len(client.nb.cells) - 1, store_history=False
386+
)
387+
except KeyError as e:
388+
# Same XEUS-based protocol violation as in cell_execute.
389+
# Cleanup failures are non-fatal: trace and continue so the
390+
# render still completes (kernel deps just won't be collected).
391+
if e.args == ("status",):
392+
trace("cleanup cell failed with missing 'status' in execute_reply; kernel deps unavailable")
393+
else:
394+
raise
386395
nb.cells.pop()
387396

388397
# record kernel deps after execution (picks up imports that occurred
@@ -574,12 +583,12 @@ def cell_execute(client, cell, index, execution_count, eval_default, store_histo
574583
# Some kernels (e.g. XEUS-based Maple) omit 'status' from
575584
# execute_reply on error, violating the Jupyter protocol.
576585
# Record the error in the cell outputs rather than crashing.
577-
if str(e) == "'status'":
586+
if e.args == ("status",):
578587
cell.outputs.append(nbformat.v4.new_output(
579588
output_type="error",
580589
ename="KernelProtocolError",
581590
evalue="Kernel returned execute_reply without status field",
582-
traceback=["Cell source:", source],
591+
traceback=[],
583592
))
584593
else:
585594
raise

0 commit comments

Comments
 (0)