Skip to content

feat: add --traceback flag for full CLI stack traces#937

Merged
lchoquel merged 7 commits into
Pipelex:devfrom
Ylsssq926:feature/cli-traceback-flag-437
May 31, 2026
Merged

feat: add --traceback flag for full CLI stack traces#937
lchoquel merged 7 commits into
Pipelex:devfrom
Ylsssq926:feature/cli-traceback-flag-437

Conversation

@Ylsssq926
Copy link
Copy Markdown

@Ylsssq926 Ylsssq926 commented May 24, 2026

Closes #437

(Re-opening from #936 with the correct `feature/` branch name targeting `dev` per the project's branch policy. Same code.)

What

Adds a global `--traceback` flag to the `pipelex` CLI that prints a Rich-formatted stack trace before the friendly error panel, for any of the structured `handle_*` errors and the `PipelexError` branch in `run` execution.

Usage:

pipelex --traceback run my-pipe ...
pipelex run --traceback my-pipe ...   # position-agnostic

Why

Issue #437: when a pipeline fails, the friendly panel hides the actual Python stack and forces users to re-run with extra debug glue. An opt-in flag keeps the default output clean while giving an easy escape hatch.

How

  • Intercepted at the `PipelexCLI.make_context` level (same pattern as `--no-logo`) so it works before or after subcommands. Stored on `ctx.obj["traceback"]`.
  • New helpers `is_traceback_requested()` / `print_traceback_if_requested()` in `pipelex/cli/error_handlers.py`.
  • All 12 `handle_*` functions and the `PipelexError` branch in `_run_core.py` call the helper before rendering the panel.

Scope decisions (open to feedback)

  • `--traceback` is intercepted in `make_context`, so it doesn't show up in `pipelex --help`. Kept consistent with the existing `--no-logo` flag. Happy to migrate both to a typer callback if you'd prefer them surfaced in help.
  • Not added to `pipelex-agent` / `pipelex-dev`: the agent CLI uses stdout for a structured JSON channel, and a Rich traceback would pollute it. Easy to add if you want it.
  • The generic `except Exception` branch in `_run_core.py` already prints an unconditional traceback via `console.print_exception`, so the flag intentionally only affects branches with a friendly panel.

Tests

10 new tests in `tests/unit/pipelex/cli/test_traceback_flag.py`:

  • `is_traceback_requested()` across the 4 context states
  • `print_traceback_if_requested()` with/without flag, asserting the Rich `Traceback` object reaches `console.print`
  • Integration on `handle_inference_setup_required_error` for both flag states
  • `PipelexCLI.make_context` interception (flag stripped from args, stored on `ctx.obj`)

Verification

  • `make agent-check` (ruff + pyright + mypy + plxt): clean
  • `make agent-test`: green for the new tests; pre-existing 9 Windows path failures in `tests/unit/pipelex/cli/` are unrelated.

Note

@airestful expressed interest 6 months ago but hasn't been assigned. Happy to defer if they'd like to pick it up.


Summary by cubic

Adds a global --traceback flag to the pipelex CLI that prints a Rich-formatted stack trace before the friendly error panel, making failures easier to debug. Addresses #437 without changing default output.

  • New Features

    • Global --traceback flag works anywhere in the command (intercepted in PipelexCLI.make_context; stored in ctx.obj["traceback"]).
    • All error handlers call print_traceback_if_requested(), so stacks show before panels across all handle_* errors and all run failure paths, including inner _execute_run exceptions (file not found, interpreter, JSON decode/type, PipelineExecutionError, PipelexError).
  • Bug Fixes

    • Wired --traceback into _execute_run inner except blocks so pipelex run prints stacks before exiting.
    • Tests: split into focused files, switched to pytest-mock, and added type annotations to satisfy pyright.

Written for commit defcdb1. Summary will update on new commits.

Review in cubic

CLI errors print a concise panel which is great for end users but
makes debugging painful when a pipe fails deep in the runtime.

Adds a global --traceback flag (intercepted in PipelexCLI.make_context,
same pattern as --no-logo) that prints a Rich Traceback before the
friendly error panel. All handle_* functions in error_handlers.py now
call print_traceback_if_requested() at the top.

Also wired into the PipelexError catch in run/_run_core.py so that
generic pipeline failures also respect the flag.

Tests: 10 new unit tests covering the helper, the flag interception,
and the integration with error handlers.
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 24, 2026

Greptile Summary

This PR adds an opt-in traceback flag for the Pipelex CLI. The main changes are:

  • Global --traceback interception in PipelexCLI.make_context.
  • Shared traceback helpers in pipelex/cli/error_handlers.py.
  • Traceback printing before structured friendly error messages.
  • New unit tests for flag storage, helper behavior, and one handler path.

Confidence Score: 3/5

This is close, but the main run failure path should be fixed before merging.

  • The new flag works for many structured error handlers.

  • Pipeline execution failures are converted to typer.Exit before the new outer traceback branch can run.

  • The affected run workflow is the primary scenario this change is meant to improve.

  • pipelex/cli/commands/run/_run_core.py

Important Files Changed

Filename Overview
pipelex/cli/commands/run/_run_core.py Adds traceback handling to the outer run wrapper, but inner execution errors can bypass it.
pipelex/cli/error_handlers.py Adds shared traceback detection and calls it from structured CLI error handlers.
pipelex/cli/_cli.py Stores the global traceback flag alongside the existing no-logo flag.

Comments Outside Diff (1)

  1. pipelex/cli/commands/run/_run_core.py, line 136-141 (link)

    P1 Run tracebacks are skipped for the main pipeline failure path. When runner.execute_pipeline() raises PipelineExecutionError or another PipelexError, _execute_run() catches it here, prints a one-line message, and converts it to typer.Exit. That means the outer execute_run() PipelexError branch added by this PR never runs, so pipelex --traceback run pipe ... still does not print the requested Rich traceback for normal pipeline execution failures.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: pipelex/cli/commands/run/_run_core.py
    Line: 136-141
    
    Comment:
    **Run tracebacks are skipped** for the main pipeline failure path. When `runner.execute_pipeline()` raises `PipelineExecutionError` or another `PipelexError`, `_execute_run()` catches it here, prints a one-line message, and converts it to `typer.Exit`. That means the outer `execute_run()` `PipelexError` branch added by this PR never runs, so `pipelex --traceback run pipe ...` still does not print the requested Rich traceback for normal pipeline execution failures.
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
pipelex/cli/commands/run/_run_core.py:136-141
**Run tracebacks are skipped** for the main pipeline failure path. When `runner.execute_pipeline()` raises `PipelineExecutionError` or another `PipelexError`, `_execute_run()` catches it here, prints a one-line message, and converts it to `typer.Exit`. That means the outer `execute_run()` `PipelexError` branch added by this PR never runs, so `pipelex --traceback run pipe ...` still does not print the requested Rich traceback for normal pipeline execution failures.

Reviews (1): Last reviewed commit: "feat: add --traceback flag to CLI for fu..." | Re-trigger Greptile

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dbbd0f7fdb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tests/unit/pipelex/cli/test_traceback_flag.py Outdated
Comment thread tests/unit/pipelex/cli/test_traceback_flag.py Outdated
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

No issues found across 4 files

Re-trigger cubic

…#937)

The new traceback test module imported MagicMock from unittest.mock
and packed several Test* classes into one file. Both violate
AGENTS.md ("never use unittest.mock; use pytest-mock", "never put
more than one TestClass into a test module"). Switch to pytest-mock
fixtures and split the module into single-class files, one per area:

- test_is_traceback_requested.py
- test_print_traceback_if_requested.py
- test_traceback_flag_error_handlers.py
- test_make_context.py

Test coverage and behaviour are unchanged.

Per Codex review on PR Pipelex#937.
@thomashebrard
Copy link
Copy Markdown
Member

Thanks @Ylsssq926 for the contribution.

One blocker before merge: the --traceback hook doesn't actually fire for the case issue #437 is about. In _execute_run() around lines 135-140, PipelineExecutionError and PipelexError are caught inside the async
function and converted to typer.Exit. The outer except typer.Exit: raise in execute_run() then re-raises before the new except PipelexError branch at line 308 can run. So pipelex --traceback run my-pipe still
prints no traceback when the pipeline itself fails — which is the actual scenario the issue describes.

Fix: add print_traceback_if_requested(get_console()) at the top of those two inner catches in _execute_run(), before the typer.secho line. While you're there, please do the same for the other five inner catches
in that function (FileNotFoundError, PipelexInterpreterError/MthdsDecodeError, json.JSONDecodeError, the second FileNotFoundError for inputs, and JsonTypeError) so --traceback behaves uniformly across the run
command.

could you also merge the dev branch inside your branch?

Ylsssq926 added 2 commits May 26, 2026 16:21
thomashebrard pointed out in Pipelex#937 that the original patch only added
print_traceback_if_requested at the outer except sites in execute_run.
The inner async _execute_run already converts PipelineExecutionError /
PipelexError / FileNotFoundError / PipelexInterpreterError /
MthdsDecodeError / json.JSONDecodeError / JsonTypeError into typer.Exit
locally, and the outer `except typer.Exit: raise` short-circuits before
the new PipelexError branch can run. So `pipelex --traceback run` was
still silent for the actual pipeline-failure scenario the issue
describes.

Add print_traceback_if_requested at the top of all seven inner except
blocks in _execute_run so the flag fires before typer.Exit propagates,
keeping the behaviour uniform across run command failure modes.

Refs: Pipelex#937
@Ylsssq926
Copy link
Copy Markdown
Author

You're right, the inner catches in _execute_run() swallow the exception before the outer except PipelexError branch can fire. Fixed in 726f832f:

  • Added print_traceback_if_requested(get_console()) at the top of all 7 inner except blocks (both FileNotFoundErrors, PipelexInterpreterError/MthdsDecodeError, json.JSONDecodeError, JsonTypeError, PipelineExecutionError, and the inner PipelexError).
  • Merged dev into the branch (no conflicts).
  • Added tests/unit/pipelex/cli/test_traceback_flag_run_core.py with 4 cases covering PipelineExecutionError, bundle FileNotFoundError, JSONDecodeError, and the flag-off path.

@thomashebrard
Copy link
Copy Markdown
Member

Great!
Can you please fix the lint ?

Also one last thing: the new test_traceback_flag_run_core.py imports MagicMock and patch from unittest.mock, which is the same rule Codex flagged on the first commit and you already fixed in the other test files. Could you switch this one to the pytest-mock MockerFixture pattern to match?

Ylsssq926 added 2 commits May 26, 2026 16:56
The test file had 6 pyright errors that only surfaced in CI (local
validation only checked pipelex/cli/, not tests/). Fixed by:
- Adding Coroutine[Any, Any, Any] and Any return type to _run_async
- Adding pyright: ignore[reportPrivateUsage] on the _execute_run import
- Moving Coroutine import into TYPE_CHECKING block per ruff TC003

Refs: Pipelex#937
Replace unittest.mock imports (MagicMock, patch) with pytest-mock
MockerFixture to match the other four traceback test files, as
requested by thomashebrard in Pipelex#937.

Refs: Pipelex#937
@Ylsssq926
Copy link
Copy Markdown
Author

Both fixed:

  1. Lint/typecheck was already addressed in `3741cba9` (pushed before your comment): added type annotations on the asyncio helper and a scoped `# pyright: ignore[reportPrivateUsage]` on the private import line.
  2. Switched `test_traceback_flag_run_core.py` to the `MockerFixture` pattern in `ce928774`: no more `unittest.mock` imports, all four test cases now match the pattern in the other traceback test files.

@lchoquel
Copy link
Copy Markdown
Member

Hi @Ylsssq926 thanks a lot for your contribution. We need a moment to check it more thoroughly as it interacts with a bunch of other changes we are working on regarding error handling.
Would be happy to discuss it in GH discussions here or on our discord.

@lchoquel
Copy link
Copy Markdown
Member

Hello @Ylsssq926,

Thanks again for this — really clean work. 🙏 The design is exactly right: intercepting --traceback in PipelexCLI.make_context to mirror the existing --no-logo flag keeps it position-agnostic without touching every command signature, and the is_traceback_requested() / print_traceback_if_requested() split is tidy and well-tested.

We test-merged your branch into our current dev locally to check it against the latest tree, and the feature itself is in great shape:

  • make agent-check (ruff + plxt + pyright + mypy) — clean
  • The full CLI test suite (unit + integration + e2e) and the full make agent-test suite — both green, including all your new traceback tests
  • Manual smoke test confirms the behavior end-to-end: without the flag you get the friendly one-liner; with --traceback you get the Rich stack trace printed before the friendly message; and it works both before and after the subcommand (pipelex run --traceback pipe ... and pipelex run pipe ... --traceback)

dev has moved on a bit since you branched, so there's one merge conflict to resolve before we can accept it. Could you rebase (or merge dev) and push? Then we'll merge.

The one conflict — pipelex/cli/commands/run/_run_core.py

On dev, MthdsDecodeError was removed from the codebase entirely (the bundle-parse path now raises only PipelexInterpreterError). Your branch still catches (PipelexInterpreterError, MthdsDecodeError), so the two sides collide on that except line. After merging dev, the import for MthdsDecodeError is already gone (that line resolves cleanly to dev's version), so the tuple would reference an undefined name.

Resolution: drop MthdsDecodeError from the except clause and keep your new traceback line. The final block should read:

        except PipelexInterpreterError as exc:
            print_traceback_if_requested(get_console())
            typer.secho(f"Failed to parse bundle '{bundle_path}': {exc}", fg=typer.colors.RED, err=True)
            raise typer.Exit(1) from exc

Suggested flow (remote name may differ on your side):

git fetch origin
git merge origin/dev
# resolve the one conflict in pipelex/cli/commands/run/_run_core.py as above
git add pipelex/cli/commands/run/_run_core.py
git commit
git push

FYI — auto-merges cleanly, no action needed

dev also reworked pipelex/cli/error_handlers.py a little (it relocated the ValidateBundleError import to pipelex.pipeline.exceptions and renamed pipe_validation_error_datapipe_validation_errors). Those don't overlap with your additions, so they merge automatically — flagging it only so nothing surprises you when you pull dev.

Optional nice-to-have

If you'd like, add a short entry under ## [Unreleased]### Added in CHANGELOG.md for the new flag. Not a blocker — we can add it on merge if you'd rather skip it.

Thanks again for the contribution and for re-targeting to dev per the branch policy!

…flag-437

# Conflicts:
#	pipelex/cli/commands/run/_run_core.py
@Ylsssq926
Copy link
Copy Markdown
Author

Thanks for the detailed review and for test-merging it! 🙏

Done — merged origin/dev and resolved the one conflict in pipelex/cli/commands/run/_run_core.py exactly as you described: dropped MthdsDecodeError from the except clause and kept the new traceback line. The block now reads:

except PipelexInterpreterError as exc:
    print_traceback_if_requested(get_console())
    typer.secho(f"Failed to parse bundle '{bundle_path}': {exc}", fg=typer.colors.RED, err=True)
    raise typer.Exit(1) from exc

The MthdsDecodeError import resolved cleanly to dev's version (gone), so there are no other references left. The error_handlers.py changes you flagged merged automatically with no surprises.

Also added a ## [Unreleased]### Added entry to CHANGELOG.md for the flag, since it was easy enough.

Should be ready to merge now — thanks again!

Copy link
Copy Markdown
Member

@lchoquel lchoquel left a comment

Choose a reason for hiding this comment

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

great!

@lchoquel lchoquel merged commit ba448fc into Pipelex:dev May 31, 2026
27 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators May 31, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants