Skip to content

Add structured error location reporting to execution errors (D128) - #258

Open
isaacbrodsky wants to merge 5 commits into
mainfrom
claude/fused-render-25-relevance-j2yr05
Open

Add structured error location reporting to execution errors (D128)#258
isaacbrodsky wants to merge 5 commits into
mainfrom
claude/fused-render-25-relevance-j2yr05

Conversation

@isaacbrodsky

@isaacbrodsky isaacbrodsky commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Summary

This change adds structured error location information (where) to all execution error responses, allowing the UI to highlight the exact line of user code that failed. Both the subprocess and in-process execution paths now report errors uniformly with file, line number, function name, and source code snippet.

Key Changes

  • Error response shape: Added where field to error objects in all execution paths. where is either null (for harness/infrastructure errors) or a dict with {file, line, func, source} pointing to the deepest user-code frame.

  • Shared error diagnostics (_binding.py):

    • trim_harness_frames(): Strips leading runner/bootstrap frames from tracebacks so user code is prominent
    • user_location(): Extracts the deepest frame in the user's script as a structured location dict, handling both runtime exceptions and SyntaxErrors
  • Subprocess execution (_child.py):

    • Uses trim_harness_frames() and user_location() to build clean tracebacks and error locations
    • Formats exceptions with format_exception_only() for harness errors (no stack) and format_exception() for user errors (with trimmed stack)
  • In-process execution (executor.py):

    • Mirrors subprocess behavior for consistency
    • Applies same frame trimming and location extraction to in-process helper errors
  • Fused engine (engine.py):

    • Added _user_location() to parse where from already-formatted traceback strings (text-based counterpart to live exception handling)
    • Extracts location from both runtime frames and SyntaxError display blocks
  • UI updates (runtime.js, template.html):

    • Display where information prominently above the full traceback
    • Shows file, line, function name, and source code snippet for quick error identification
  • Tests (test_executor.py, test_engine.py):

    • Comprehensive test coverage for error location extraction across different error types
    • Validates that harness errors have where=null and user errors point to the correct frame

Implementation Details

  • Both execution paths (subprocess and in-process) use identical logic from _binding.py to ensure consistent error reporting
  • Harness-raised errors (missing params, missing main, unserializable return) have where=null and no stack trace
  • User-code errors point at the deepest frame in the user's file, even when the error originated in a library
  • SyntaxErrors are handled specially since they don't produce runtime frames—location comes from the exception object itself
  • Frozen importlib bootstrap frames are filtered out to reduce noise in tracebacks

https://claude.ai/code/session_01Ad7XvN7x4887vZoe4VP24h


Note

Low Risk
Additive error payload and UI-only display changes; existing consumers that ignore where keep working, with broad test coverage on both execution paths.

Overview
Python run failures now return a structured where (file, line, func, source) on the deepest frame in the user script, with traceback trimmed so it no longer leads with _child.py / executor harness frames. Harness-only failures (bad params, missing main, timeouts, missing file) keep where: null and often a message-only traceback.

Shared helpers trim_harness_frames and user_location in _binding.py drive both the subprocess worker and in-process executor; the fused engine adds _user_location to parse the same shape from cleaned traceback text. Specs, architecture notes, and authoring docs are updated for the wire shape (PY-14 / RH-3).

runtime.js and the API inspector template headline the failing line when where is present, collapse the full traceback behind Show traceback (sr-only so select-all still copies it), and add Copy error. New tests/test_executor.py and engine tests cover deepest-frame semantics, library errors blaming the caller, syntax errors, and harness cases.

Reviewed by Cursor Bugbot for commit 31bc606. Bugbot is set up for automated code reviews on this repo. Configure here.

Rework of the stale draft that became PR #25. A run failure's red overlay
led with the runner's own frame (_child.py's `fn(**bind_params(...))`) and
buried the user's actual line further down. Now the traceback starts at the
caller's code and a structured `where` points straight at the failing line.

- _binding.py: shared `trim_harness_frames` + `user_location`, used by both
  built-in execution paths so they report failures identically.
- _child.py (subprocess/user code) and executor.py `_run_inprocess`
  (in-process first-party helpers): trim leading runner frames (this module,
  _binding.py, `<frozen importlib>`); harness-raised errors (bad params,
  missing main, unserializable return) format as the exception line only;
  add `error.where` = {file, line, func, source} of the deepest frame in the
  user's own file, or null when the error never touched it.
- executor.py `_error()` (missing file, timeout, worker crash): where=null.
- engine.py (fused engine): text-based `_user_location` over the cleaned
  traceback string, matching the same semantics — one wire shape (PY-14).
- runtime.js overlay + api/template.html: headline `<file>, line N, in
  <func>` + the source line above the traceback. Additive wire change;
  existing {type,message,traceback} consumers unaffected.
- Docs: ARCHITECTURE, SPEC (RH-3/PY-14), SKILL, and DECISIONS D128
  (renumbered from the draft's D72, since taken by the in-process split;
  reconciled against the _binding.py extraction and the in-process path).
- Tests: new tests/test_executor.py (real subprocesses) + engine `where`
  cases.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ad7XvN7x4887vZoe4VP24h
@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  fused_render
  _binding.py 36-41, 54-70, 75
  _child.py 23-34, 65-77
  engine.py
  executor.py 146-155
  server.py 3737
Project Total  

This report was generated by python-coverage-comment-action

After trimming, the traceback already leads with the user's failing frame,
so the where headline rendered inline above it duplicated that line (and its
source) for errors raised directly in user code. Make the headline the
prominent culprit and tuck the full traceback behind a collapsed `Traceback`
toggle on both surfaces (runtime overlay + api card). When there is no
`where` (harness error, timeout, missing file) the traceback shows outright,
since it is the only content. Display-only — the wire shape is unchanged.

Docs: ARCHITECTURE error-overlay bullet, SKILL, DECISIONS D128.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ad7XvN7x4887vZoe4VP24h
Comment thread fused_render/static/runtime.js Outdated
Bugbot (PR #258): a SyntaxError always sets `where`, so the previous commit
collapsed its traceback behind the toggle. But that traceback is the
`format_exception_only` caret block, and its `^` column marker (the exact bad
token) is not captured in `where` — so the caret was hidden by default on a
common failure path.

Fix: for a SyntaxError/IndentationError/TabError, show the traceback outright
with no headline (the caret block already names file/line/column and is a
better pointer than the headline we build). Runtime errors keep the
headline + collapsed traceback. Both surfaces (overlay + api card). Docs:
ARCHITECTURE, DECISIONS D128.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ad7XvN7x4887vZoe4VP24h

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 214be36. Configure here.

Comment thread fused_render/_child.py
claude added 2 commits July 23, 2026 22:41
…ct-all

Collapsing the traceback behind a <details> hid it with display:none, which
the browser also excludes from select-all/copy — so copying the whole page
(e.g. to paste into an AI) lost the full stack.

Fix, both surfaces (runtime overlay + api card):
- Add a "Copy error" button that writes the entire debug message (type +
  message + full traceback) to the clipboard (clipboard API, with a
  hidden-textarea + execCommand fallback for the sandboxed iframe / non-secure
  origins). Guaranteed way to copy everything regardless of what's on screen.
- Replace the display:none collapse with an sr-only (clip-rect) <pre>: the
  traceback is invisible on screen but STILL captured by a whole-page
  select-all, and it's one node so expanding (Show traceback) never
  double-copies. Verified in Chromium that clip-rect survives select-all where
  display:none / <details> do not.

Headline stays primary; SyntaxError caret block and no-`where` errors still
render outright. Docs: ARCHITECTURE, DECISIONS D128, SKILL.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ad7XvN7x4887vZoe4VP24h
…5-relevance-j2yr05

# Conflicts:
#	DECISIONS.md
#	skills/fused-render-authoring/SKILL.md
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.

2 participants