Skip to content

Comments

Improve timeout error messages with structured context#11

Merged
lambdalisue merged 2 commits intomainfrom
fix/timeout-error
Jan 7, 2026
Merged

Improve timeout error messages with structured context#11
lambdalisue merged 2 commits intomainfrom
fix/timeout-error

Conversation

@lambdalisue
Copy link
Member

Summary

  • Add StepTimeoutError class with step name, timeout value, attempt number, and elapsed time
  • Add ScenarioTimeoutError class with scenario name, timeout value, and elapsed time
  • Add timeout field to RunOptions for scenario-level timeout configuration
  • Implement timeout enforcement in Runner using deadline and AbortSignal
  • Add comprehensive tests for both step and scenario timeout behavior

Why

Previously, timeout errors showed only generic "TimeoutError" messages without context about which step or scenario failed, what the timeout limit was, or how long execution actually took. This made debugging timeout issues difficult in complex test scenarios.

These changes address two use cases:

  1. Step-level timeouts: Users needed to know which specific step timed out, especially in scenarios with multiple steps and retry logic. The new StepTimeoutError includes the step name, configured timeout, retry attempt number, and total elapsed time.

  2. Scenario-level timeouts: Users needed to bound the cumulative execution time of all steps in a scenario to prevent long-running scenarios from blocking test suite completion. The new RunOptions.timeout provides independent timeout control for each scenario, separate from step-level timeouts.

The implementation follows a consistent pattern (deadline + AbortSignal + structured error) for maintainability. Each scenario's timeout is enforced independently, so one timeout doesn't affect other scenarios' execution.

Test Plan

  • Run deno task verify - all tests pass
  • Verify step timeout error includes step name, timeout value, attempt number, and elapsed time
  • Verify scenario timeout error includes scenario name, timeout value, and elapsed time
  • Verify timeout with retry configured only attempts once (retry is canceled by AbortSignal)
  • Verify multiple scenarios with independent timeouts work correctly
  • Verify scenarios run normally when no timeout is specified

Copilot AI review requested due to automatic review settings January 7, 2026 14:09
Step timeout errors previously showed only generic "TimeoutError" messages
without indicating which step failed, the configured timeout value, or
total elapsed time. This made debugging timeout issues difficult in
complex scenarios with multiple steps.

The new StepTimeoutError includes:
- stepName: identifies the failing step
- timeoutMs: configured timeout value
- attemptNumber: retry attempt when timeout occurred
- elapsedMs: total execution time including retries

This structured error information enables better error reporting and
programmatic error handling in reporters and test frameworks.
Users can now set timeout limits for entire scenarios via RunOptions.timeout,
providing control over scenario execution time independent of step-level
timeouts. This addresses cases where the cumulative time of all steps in a
scenario needs to be bounded, preventing long-running scenarios from blocking
test suite completion.

The implementation follows the same pattern as step timeout (deadline +
AbortSignal + structured error), ensuring consistency and maintainability.
Each scenario's timeout is enforced independently, so one timeout doesn't
affect other scenarios' execution.

- Add ScenarioTimeoutError with scenarioName, timeoutMs, and elapsedMs
- Add timeout field to RunOptions interface
- Implement timeout enforcement in Runner using deadline and AbortSignal
- Add comprehensive tests for timeout behavior
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 enhances timeout error handling by introducing structured error classes that provide detailed context when steps or scenarios time out. Previously, timeout errors showed only generic "TimeoutError" messages. Now they include the step/scenario name, configured timeout value, attempt number (for steps), and actual elapsed time.

Key Changes:

  • Added StepTimeoutError and ScenarioTimeoutError classes with structured fields for better debugging
  • Implemented scenario-level timeout configuration via RunOptions.timeout field
  • Added retry attempt tracking to timeout errors using internal metadata

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/probitas-runner/errors.ts New file defining StepTimeoutError and ScenarioTimeoutError with structured context
packages/probitas-runner/utils/retry.ts Attaches retry attempt metadata to errors for context in timeout errors
packages/probitas-runner/step_runner.ts Enriches timeout errors with retry context and elapsed time
packages/probitas-runner/runner.ts Implements scenario-level timeout enforcement using deadline and AbortSignal
packages/probitas-runner/types/run.ts Adds timeout field to RunOptions for scenario-level timeout configuration
packages/probitas-runner/step_runner_test.ts Comprehensive tests for step timeout behavior with and without retry
packages/probitas-runner/runner_test.ts Tests for scenario timeout with independent timeout handling and normal execution
packages/probitas-runner/mod.ts Updates documentation to reference new error types and exports them

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

Comment on lines +21 to +27
/**
* Error with retry metadata attached
* @internal
*/
interface ErrorWithRetryMetadata extends Error {
__retryAttemptNumber?: number;
}
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

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

The ErrorWithRetryMetadata interface is defined identically in both this file and utils/retry.ts. Consider moving this to a shared location (e.g., a types file) or re-exporting it from one location to avoid duplication and ensure consistency.

Copilot uses AI. Check for mistakes.
Comment on lines +164 to +166
function isTimeoutError(error: unknown): boolean {
return error instanceof DOMException && error.name === "TimeoutError";
}
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

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

The isTimeoutError function is duplicated in both runner.ts and step_runner.ts. Consider extracting this to a shared utility file to avoid duplication and ensure consistency.

Copilot uses AI. Check for mistakes.
@codecov
Copy link

codecov bot commented Jan 7, 2026

Codecov Report

❌ Patch coverage is 80.59701% with 26 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
packages/probitas-runner/runner.ts 75.00% 17 Missing ⚠️
packages/probitas-runner/errors.ts 85.41% 7 Missing ⚠️
packages/probitas-runner/step_runner.ts 88.23% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@lambdalisue lambdalisue merged commit c023b29 into main Jan 7, 2026
3 checks passed
@lambdalisue lambdalisue deleted the fix/timeout-error branch January 7, 2026 14:23
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.

1 participant