Skip to content

Improve timeout error reporting with signal-based error propagation#94

Merged
lambdalisue merged 3 commits intomainfrom
refactor/timeout
Jan 8, 2026
Merged

Improve timeout error reporting with signal-based error propagation#94
lambdalisue merged 3 commits intomainfrom
refactor/timeout

Conversation

@lambdalisue
Copy link
Member

Summary

  • Refactor CLI subprocess to delegate timeout handling to Runner
  • Update runner package to v0.5.6 with signal-based timeout error propagation
  • Add comprehensive timeout failure test scenarios

Why

Previously, timeout errors were indistinguishable - whether a step failed due to its own timeout or the scenario's overall timeout, both appeared as generic timeout errors. This made debugging difficult.

The CLI subprocess previously combined timeout and manual abort signals using AbortSignal.any(), which conflated two concerns:

  • Timeout enforcement (scenario-level timeout)
  • Manual cancellation (Ctrl-C, --fail-fast)

This refactor separates these concerns by:

  1. Passing timeout as a dedicated option to Runner.run()
  2. Allowing Runner to create timeout signals internally with proper error types
  3. Propagating timeout reasons through the signal chain via AbortSignal.reason

The result is clear, actionable error messages:

  • StepTimeoutError: Step exceeded its own timeout setting
  • ScenarioTimeoutError: Scenario timeout triggered, with context about which step was executing

Test Plan

  • Step timeout shows StepTimeoutError with correct timing
  • Scenario timeout shows ScenarioTimeoutError with step context
  • Error messages clearly distinguish timeout source
  • Test scenarios validate both timeout types

Previously, the CLI subprocess combined timeout and manual abort signals
using AbortSignal.any(). This approach conflated two concerns:
- Timeout enforcement (scenario-level timeout)
- Manual cancellation (Ctrl-C, --fail-fast)

Now, the subprocess passes timeout as a separate option to Runner.run(),
allowing Runner to distinguish between scenario timeouts and external
cancellations. This enables accurate timeout error reporting with proper
ScenarioTimeoutError vs StepTimeoutError distinction.

The Runner internally creates timeout signals and properly propagates
timeout reasons through the signal chain, resulting in clear error
messages that indicate whether a timeout was caused by:
- Step's own timeout setting (StepTimeoutError)
- Scenario-wide timeout (ScenarioTimeoutError with step context)
Updates:
- @probitas/runner: ^0.5.1 → ^0.5.6
- @probitas/builder: ^0.5.1 → ^0.5.2
- @probitas/core: ^0.3.1 → ^0.3.2

The runner update includes improved timeout error handling with
signal-based error propagation, enabling proper distinction between
StepTimeoutError and ScenarioTimeoutError.
Adds comprehensive test scenarios to verify timeout error handling:

- Step timeout: Individual step exceeds its configured timeout
- Step timeout with retry: All retry attempts timeout
- Scenario timeout: Scenario-level timeout triggers during step execution

These scenarios validate that:
- StepTimeoutError is reported when step's own timeout is exceeded
- ScenarioTimeoutError is reported with step context when scenario timeout triggers
- Error messages clearly distinguish the timeout source
Copilot AI review requested due to automatic review settings January 8, 2026 14:34
@lambdalisue lambdalisue enabled auto-merge January 8, 2026 14:35
@lambdalisue lambdalisue merged commit 0464302 into main Jan 8, 2026
9 checks passed
@lambdalisue lambdalisue deleted the refactor/timeout branch January 8, 2026 14:37
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors timeout error handling to provide clearer, more actionable error messages by separating timeout enforcement from manual cancellation. The CLI subprocess now delegates timeout handling to the Runner package, which uses signal-based error propagation to distinguish between step-level and scenario-level timeouts.

Key changes:

  • Refactored CLI subprocess to pass timeout as a dedicated Runner option instead of combining it with abort signals
  • Updated @probitas/runner to v0.5.6, @probitas/builder to v0.5.2, and @probitas/core to v0.3.2 to support signal-based timeout error propagation
  • Added comprehensive timeout failure test scenarios covering step timeouts, retry behavior, and scenario-level timeouts

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated no comments.

File Description
src/cli/_templates/run.ts Removes AbortSignal.any() combining timeout and manual abort; passes timeout as a dedicated option to Runner
probitas/100-failure-timeout.probitas.ts New test file demonstrating step timeout, step timeout with retry, and scenario timeout scenarios
deno.json Updates dependency versions for @probitas/runner (0.5.6), @probitas/builder (0.5.2), and @probitas/core (0.3.2)
deno.lock Synchronizes lockfile with updated dependency versions and transitive dependencies

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

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