Skip to content

Preserve voice transcription transport errors' cause and actionability - #15290

Merged
acarl005 merged 1 commit into
masterfrom
factory/quality-1231-voice-transcribe-error-actionability
Aug 19, 2026
Merged

Preserve voice transcription transport errors' cause and actionability#15290
acarl005 merged 1 commit into
masterfrom
factory/quality-1231-voice-transcribe-error-actionability

Conversation

@warp-agent-staging

@warp-agent-staging warp-agent-staging Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Description

Voice transcription transport failures (Error: Failed to transcribe CLI voice input and its GUI sibling) were one of the noisiest client Sentry surfaces (~90k+ events, ~6k users, ~3-4k/day), because TranscribeError::Transport was a unit variant with no #[source], and TranscribeError::Deserialization was too. ServerApi::transcribe dropped the underlying reqwest::Error (any non-429 HTTP status, and any failure reading/decoding the response body) after a local log::warn!, so every event reached Sentry with an identical, causeless message and no way to tell connect vs. timeout vs. 5xx vs. a truncated body apart. Because TranscribeError was never registered via register_error!/impl ErrorExt, it defaulted to is_actionable() == true, so ordinary network flakiness paged engineering on every occurrence.

This mirrors the existing AIApiError treatment (crates/warp_errors/src/reqwest.rs, impl ErrorExt for AIApiError, and its DeserializationError split / from_transport_error hyper-source walk) that a prior PR (#14292) applied to the multi-agent path but never touched voice.

Changes

  • TranscribeError::Transport now carries the source reqwest::Error instead of discarding it.
  • Non-429 non-success HTTP statuses get their own ErrorStatus(http::StatusCode) variant instead of being collapsed into the unit Transport, so status is preserved.
  • TranscribeError::Deserialization now carries a DeserializationError (shared with AIApiError) instead of being a source-less unit variant. TranscribeError::from_json_error classifies a reqwest::Error from Response::json(): a decode error whose source chain contains a hyper::Error (reqwest sometimes misreports a mid-stream disconnect/timeout as a decode error) or any other non-decode failure routes to Transport; a genuine decode failure routes to Deserialization(DeserializationError::Transport(_)). This mirrors AIApiError::from_transport_error.
  • Added impl ErrorExt for TranscribeError + register_error!(TranscribeError):
    • Transport delegates to reqwest::Error::is_actionable() (connect/request/body/decode, 429, 5xx, staging 403 → not actionable).
    • ErrorStatus is not actionable for 5xx/429 (server-side), actionable for other 4xx (real client-side defect).
    • QuotaLimit/ServerOverloaded are not actionable (expected, user-visible conditions).
    • Deserialization(Json(_)) stays actionable (a real JSON contract bug); Deserialization(Transport(_)) delegates to the wrapped reqwest::Error.
    • Other delegates to the wrapped anyhow::Error.
  • No behavior change for users: both CLI (agent_input_footer) and GUI (editor/view/voice.rs) sinks already call report_error!(anyhow::Error::new(e).context(...)) typed, unchanged; the error toast and log::warn! breadcrumbs are unchanged. Only the Sentry actionability classification (and the cause/status now present in the reported chain) changes.
  • AIApiError (the multi-agent path from Preserve transport error actionability in Sentry reports #14292) is untouched.

Linked Issue

QUALITY-1231

Testing

  • No tests are included: unit tests covering TranscribeError's is_actionable() classification were written and passing, then removed at the reviewer's request, along with the comments this change had added. The classification therefore has no automated regression guard.

  • rustfmt --check on the touched file — clean.

  • Compilation is verified by CI; the branch has been rebased onto current master.

  • No UI surface change (pure Rust error-classification change), so no visual verification was needed.

  • I have manually tested my changes locally with ./script/run

Agent Mode

  • Warp Agent Mode - This PR was created via Warp's AI Agent Mode

CHANGELOG-NONE

@warp-agent-staging

Copy link
Copy Markdown
Contributor Author

This PR was generated with Warp.

Comment @warp-factory on this PR to send it follow-up work.

View run View conversation

@acarl005
acarl005 marked this pull request as ready for review August 19, 2026 00:42
TranscribeError::Transport was a unit variant that discarded the
voice sinks report every non-quota failure, so ordinary network flakiness
defaulted to actionable and flooded Sentry with a static, causeless
message (~92k events / ~5.9k users since mid-July).

Carry the source error, split non-429 statuses into their own variant,
classify JSON contract failures separately from body reads that fail
after headers, and register actionability so transport failures delegate
to reqwest::Error::is_actionable().

QUALITY-1231
@warp-agent-staging
warp-agent-staging Bot force-pushed the factory/quality-1231-voice-transcribe-error-actionability branch from 9fda660 to 3f2974c Compare August 19, 2026 01:07
@acarl005 acarl005 self-assigned this Aug 19, 2026
@acarl005
acarl005 merged commit d80cffd into master Aug 19, 2026
32 checks passed
@acarl005
acarl005 deleted the factory/quality-1231-voice-transcribe-error-actionability branch August 19, 2026 01:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant