Skip to content

fix(workflows): route 'workflow status --json' errors to stderr#3520

Open
jawwad-ali wants to merge 2 commits into
github:mainfrom
jawwad-ali:fix/workflow-status-json-stderr
Open

fix(workflows): route 'workflow status --json' errors to stderr#3520
jawwad-ali wants to merge 2 commits into
github:mainfrom
jawwad-ali:fix/workflow-status-json-stderr

Conversation

@jawwad-ali

Copy link
Copy Markdown
Contributor

What

specify workflow status <run_id> --json printed its lookup errors to stdout, corrupting the machine-readable JSON stream.

In workflow_status, the two run_id error handlers used the stdout console and fire before the if json_output: branch:

except FileNotFoundError:
    console.print(f"[red]Error:[/red] Run not found: {run_id}")   # -> stdout
except ValueError as exc:
    console.print(f"[red]Error:[/red] {_escape_markup(str(exc))}")  # -> stdout

So a consumer doing json.loads(stdout) on specify workflow status bad-id --json gets a Rich-rendered error line instead of parseable JSON.

Fix

Route both handlers through the existing _error_console(json_output) helper so they go to stderr under --json. This mirrors the sibling commands in the same file — workflow run (err.print(...), line ~1083) and workflow resume, which does the identical RunState.load try/except with the byte-identical Run not found: {run_id} message routed to stderr (line ~1188) — and the documented stdout-purity contract on _emit_workflow_json/_error_console. One file, minimal change; text output path is unchanged.

Test

test_status_json_not_found_error_goes_to_stderr asserts that under --json the not-found error appears on stderr and stdout stays empty (no partial JSON). Fails before the fix (the error was on stdout), passes after. Existing status boundary tests unchanged.

uvx ruff check  # clean
uv run pytest tests/test_workflows.py -k "status_json_not_found or status_run_not_found or status_no_run_id"  # pass

🤖 This PR was written with the assistance of Claude Code (AI). The bug was self-found and the fix/tests were verified locally (fail-before / pass-after).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Routes workflow status JSON-mode lookup errors to stderr, preserving clean stdout for machine-readable output.

Changes:

  • Uses _error_console(json_output) for status lookup errors.
  • Adds a regression test for missing runs.
Show a summary per file
File Description
src/specify_cli/workflows/_commands.py Routes status errors appropriately.
tests/test_workflows.py Tests stderr routing for missing runs.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Medium

Comment thread tests/test_workflows.py
@mnriem

mnriem commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

Please address Copilot feedback

jawwad-ali and others added 2 commits July 15, 2026 10:29
The workflow_status run_id error paths (FileNotFoundError -> 'Run not found',
ValueError -> invalid run) used the stdout console and fired before the
json_output branch, so 'specify workflow status <bad-id> --json' wrote a
Rich-rendered error to stdout and corrupted the JSON stream a consumer would
json.loads(). Route both through _error_console(json_output) so they go to
stderr under --json, matching the sibling 'workflow run'/'workflow resume'
commands (which use the identical RunState.load try/except) and the documented
stdout-purity contract.

Test asserts the not-found error appears on stderr and stdout stays empty under
--json (fails before: the error was on stdout).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…on purity

The stderr-routing fix reroutes both the FileNotFoundError and ValueError run_id
handlers, but the test only exercised FileNotFoundError — a regression of the
ValueError path back to stdout would have gone uncaught. Add a ValueError case
(RunState.load raising) asserting the same stderr-only / empty-stdout behavior.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jawwad-ali jawwad-ali force-pushed the fix/workflow-status-json-stderr branch from 77743e8 to de544bc Compare July 15, 2026 05:34
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.

3 participants