Skip to content

bug(task): preserve actionable provider errors on non-zero exits #873

Description

@EivMeyer

Problem

A standalone zeroshot task run can finish with status: failed and error: null even when the provider printed an actionable failure reason.

On current main:

  • consumeStderr() writes stderr to the log but does not retain a diagnostic.
  • complete() populates error only for the special fatal detector, session-identity failure, or signal termination.
  • detectProviderFatalError() is Claude-only and currently recognizes one fatal text pattern.
  • A provider-agnostic classifyProviderError() already exists, but the watcher terminal path does not use it.

This was observed with Gemini exiting 1 after printing IneligibleTierError / UNSUPPORTED_CLIENT: the useful cause remained buried in the log while task status exposed no error. Similar ordinary non-zero Claude exits can have the same result.

The provider rejecting a request is external. Zeroshot discarding the reason is the core bug.

Expected behavior

Every unsuccessful provider exit should persist a bounded, sanitized, actionable failure summary and surface it through task status / inspect.

Acceptance criteria

  • A non-zero exit without a signal produces a non-empty task error when the provider emitted a diagnostic.
  • Terminal handling uses the registered provider adapter's error classifier for every provider.
  • The persisted result distinguishes at least retryable vs permanent/unsupported failures.
  • Diagnostic capture is bounded and redacts likely credentials/secrets; complete raw output remains in the task log.
  • Signal-only failures and existing session-identity failures retain their more specific reasons.
  • Successful exits are unchanged.
  • Fake-provider tests cover non-zero stderr/stdout failures for at least Claude, Codex, and Gemini, including the no-signal case.
  • zeroshot task status and zeroshot inspect show the persisted reason without requiring users to mine the log.

Related

#152 covers cluster-level provider retry/recovery. This issue is the narrower standalone task watcher/status boundary.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions