Skip to content

fix(tower-runtime): preserve error details in SpawnFailed and PackageUnpackFailed#285

Open
sammuti wants to merge 1 commit into
mainfrom
fix/preserve-error-details-in-runtime-errors
Open

fix(tower-runtime): preserve error details in SpawnFailed and PackageUnpackFailed#285
sammuti wants to merge 1 commit into
mainfrom
fix/preserve-error-details-in-runtime-errors

Conversation

@sammuti
Copy link
Copy Markdown
Contributor

@sammuti sammuti commented Jun 1, 2026

Summary

  • Add detail: String field to Error::SpawnFailed and Error::PackageUnpackFailed so the root cause (IO error, missing uv, permission denied, etc.) flows through to termination logs and trace spans
  • Add Display impl for tower_uv::Error
  • Previously all tower_uv::Error variants were mapped to a bare Error::SpawnFailed with no context, making production spawn_failed errors impossible to diagnose without pod-level access

Context

Investigating TOW-2151/TOW-2160 (WaiterClosed) and recent spawn_failed errors on May 31, we found that while the structured AppCompletion::Failed pipeline (from #274) correctly surfaces the error kind, the actual error message was always just "SpawnFailed" because the From<tower_uv::Error> impl discarded the inner detail.

After this change, termination logs and trace spans will show messages like:

  • spawning process: not found: uv binary not found in PATH
  • spawning process: IO error: No such file or directory (os error 2)
  • spawning process: permission denied: /app/.venv/bin/python
  • package unpack failed: InvalidManifest

Test plan

  • cargo check --workspace passes
  • cargo test --workspace passes
  • Deploy to staging and trigger a run with a broken pyproject.toml to verify the detail appears in traces

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved error messages with detailed context for spawn failures and package operations, helping users better understand what went wrong during runtime execution.

…UnpackFailed

Previously, `From<tower_uv::Error>` and `From<std::io::Error>` conversions
discarded the inner error message, making `SpawnFailed` and
`PackageUnpackFailed` uninformative in logs and traces. The termination
log and trace spans would just show "SpawnFailed" with no context about
whether uv was missing, a permission was denied, pyproject.toml was
absent, etc.

Add a `detail: String` field to both variants and propagate the original
error message through the conversion. Also add `Display` impl for
`tower_uv::Error` so it can be stringified cleanly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 1, 2026

⚠️ WARNING: This PR targets main instead of develop

This PR is targeting main which will trigger a production deployment when merged.

If this is a regular feature/fix PR, please change the base branch to develop.
If this is intentional (e.g., hotfix), you can ignore this warning.

Current base: main
Recommended base: develop

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 1, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

Error variants SpawnFailed and PackageUnpackFailed are extended with detail strings, their display messages are updated, From trait implementations are enriched to capture error details, a Display trait is added to tower_uv::Error, and subprocess error handling is updated to populate these detail fields with specific context.

Changes

Error Detail Enrichment

Layer / File(s) Summary
Error variant definitions and display messages
crates/tower-runtime/src/errors.rs
SpawnFailed and PackageUnpackFailed are changed from unit variants to struct variants carrying detail: String, with Snafu display strings updated to interpolate the detail.
Display trait for tower_uv::Error
crates/tower-uv/src/lib.rs
Display is implemented for tower_uv::Error, formatting each variant into human-readable strings to support to_string() calls in error conversions.
From trait implementations to populate error details
crates/tower-runtime/src/errors.rs
From<std::io::Error>, From<tower_uv::Error>, and From<tower_package::Error> implementations are updated to map upstream errors into struct variants with details captured via to_string().
Subprocess error handling enriched with detail
crates/tower-runtime/src/subprocess.rs
receive_and_unpack_package and backend create methods populate PackageUnpackFailed detail with formatted error context for unpack failures and missing invariant states.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 Errors now carry their stories with care,
With details and strings beyond bare despair,
From IO to UV, each mishap now speaks,
The devils are caught in the error technique!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding detail fields to error variants to preserve error context.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/preserve-error-details-in-runtime-errors

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 1, 2026

⚠️ WARNING: This PR targets main instead of develop

This PR is targeting main which will trigger a production deployment when merged.

If this is a regular feature/fix PR, please change the base branch to develop.
If this is intentional (e.g., hotfix), you can ignore this warning.

Current base: main
Recommended base: develop

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
crates/tower-runtime/src/errors.rs (1)

82-85: ⚡ Quick win

Standardize I/O detail formatting in spawn conversion.

Line 84 currently uses raw err.to_string(), so this path omits the IO error: prefix used by tower_uv::Error::IoError. Prefixing here keeps SpawnFailed messages consistent across conversion paths.

Suggested patch
 impl From<std::io::Error> for Error {
     fn from(err: std::io::Error) -> Self {
         Error::SpawnFailed {
-            detail: err.to_string(),
+            detail: format!("IO error: {err}"),
         }
     }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/tower-runtime/src/errors.rs` around lines 82 - 85, The SpawnFailed
conversion currently uses err.to_string() directly; change the conversion in the
From<std::io::Error> implementation so the detail string is prefixed with "IO
error: " (e.g., build the detail as format!("IO error: {}", err)) to match the
formatting used by tower_uv::Error::IoError and keep Error::SpawnFailed messages
consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@crates/tower-runtime/src/errors.rs`:
- Around line 82-85: The SpawnFailed conversion currently uses err.to_string()
directly; change the conversion in the From<std::io::Error> implementation so
the detail string is prefixed with "IO error: " (e.g., build the detail as
format!("IO error: {}", err)) to match the formatting used by
tower_uv::Error::IoError and keep Error::SpawnFailed messages consistent.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2fdfb143-4d30-4bf4-bda0-8a3665bba3ae

📥 Commits

Reviewing files that changed from the base of the PR and between c4e63f8 and 90a256b.

📒 Files selected for processing (3)
  • crates/tower-runtime/src/errors.rs
  • crates/tower-runtime/src/subprocess.rs
  • crates/tower-uv/src/lib.rs

Copy link
Copy Markdown
Contributor

@bradhe bradhe left a comment

Choose a reason for hiding this comment

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

Looks good. Just fix failing CI.

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