openai/codex · critical · CodexErr

Fatal error: {0}

Error message

Fatal error: {0}

What it means

CodexErrorDetails::Fatal(String) at error.rs:164-165 prints 'Fatal error: {0}' for conditions the session cannot recover from. It is non-retryable (is_retryable returns false, error.rs:370) and falls through to CodexErrorInfo::Other at the protocol boundary (error.rs:454), so hosts should stop the turn or session and surface the message instead of attempting automatic recovery.

Source

Thrown at codex-rs/protocol/src/error.rs:164

    UsageNotIncluded,
    #[error("We're currently experiencing high demand, which may cause temporary errors.")]
    InternalServerError,
    /// Retry limit exceeded.
    #[error("{0}")]
    RetryLimit(RetryLimitReachedError),
    /// Agent loop died unexpectedly
    #[error("internal error; agent loop died unexpectedly")]
    InternalAgentDied,
    /// Sandbox error
    #[error("sandbox error: {0}")]
    Sandbox(#[from] SandboxErr),
    #[error("codex-linux-sandbox was required but not provided")]
    LandlockSandboxExecutableNotProvided,
    #[error("unsupported operation: {0}")]
    UnsupportedOperation(String),
    #[error("{0}")]
    RefreshTokenFailed(RefreshTokenFailedError),
    #[error("Fatal error: {0}")]
    Fatal(String),
    // -----------------------------------------------------------------
    // Automatic conversions for common external error types
    // -----------------------------------------------------------------
    #[error(transparent)]
    Io(#[from] io::Error),
    #[error(transparent)]
    Json(#[from] serde_json::Error),
    #[cfg(target_os = "linux")]
    #[error(transparent)]
    LandlockRuleset(#[from] landlock::RulesetError),
    #[cfg(target_os = "linux")]
    #[error(transparent)]
    LandlockPathFd(#[from] landlock::PathFdError),
    #[error(transparent)]
    TokioJoin(#[from] JoinError),
    #[error("{0}")]
    EnvVar(EnvVarError),

View on GitHub (pinned to 339751715c)

Solutions

  1. Stop the current thread or session - do not retry; the variant is non-retryable by classification.
  2. Read the {0} payload; it names the underlying unrecoverable condition.
  3. Check environment basics: disk space and permissions on CODEX_HOME and session storage.
  4. Start a fresh thread; if resuming a rollout triggered it, inspect or discard that rollout file.
  5. If reproducible, capture the payload and report via /feedback - Fatal often marks an internal defect.

Example fix

// before: logging and continuing
if let Err(e) = session.run().await {
    log::error!("{e}"); // keeps a corrupted session alive
}

// after: treat Fatal as terminal
match err.details() {
    CodexErrorDetails::Fatal(msg) => {
        session.shutdown().await?;
        report_and_exit(msg);
    }
    _ => return Err(err.into()),
}
Defensive patterns

Strategy: try-catch

Type guard

fn is_fatal(err: &CodexErr) -> bool {
    matches!(err.details(), CodexErrorDetails::Fatal(_))
}

Try / catch

Err(err) if matches!(err.details(), CodexErrorDetails::Fatal(_)) => {
    // halt the agent loop, persist nothing further, surface the message
    halt_and_report(&err).await;
}

Prevention

When it happens

Trigger: Constructed via CodexErr::Fatal(message) (error.rs:335) on unrecoverable internal conditions where no dedicated variant exists - for example session or rollout state that can no longer be persisted or trusted. By design it marks state you must not keep operating on.

Common situations: Disk-full or permission failures while writing rollout/session state escalated to fatal; resuming a truncated or corrupted rollout file; internal defects that lack a specific error variant.

Related errors


AI-assisted analysis of openai/codex@339751715c (2026-08-25). Data as JSON: /api/errors/9924aa6814724dc9. Report an issue: GitHub.