Hmbown/CodeWhale · error

Codex client

Error message

Codex client

What it means

A panic from `CodewhaleClient::new(&config).expect("Codex client")` in the credential-snapshot test. Client construction resolves the Codex bearer token and account id from the OPENAI_CODEX_AUTH_FILE fixture (with OPENAI_CODEX_ACCESS_TOKEN / CODEX_ACCESS_TOKEN removed) and validates them; construction fails when credential resolution or required client setup fails — e.g. the auth file content is rejected or a TLS/crypto provider could not be initialized.

Solutions

  1. Validate the fixture auth.json is exactly {"tokens":{"access_token":<valid JWT>,"account_id":"..."}} and the JWT is well-formed base64url with future exp.
  2. Ensure crate::test_support::lock_test_env() guards OPENAI_CODEX_AUTH_FILE / OPENAI_CODEX_ACCESS_TOKEN / CODEX_ACCESS_TOKEN so parallel tests cannot leak values.
  3. Install the crypto provider before constructing clients (rustls::crypto::ring::default_provider().install_default()), as done in client_with_config_secret_sentinels.
  4. Run the single test with --test-threads=1 to rule out cross-test env pollution, then bisect.

Example fix

// before
let client = CodewhaleClient::new(&config).expect("Codex client");
// after (defensively, in test setup)
let _ = rustls::crypto::ring::default_provider().install_default();
let client = CodewhaleClient::new(&config)
    .unwrap_or_else(|e| panic!("Codex client: {e:?}"));
Defensive patterns

Strategy: validation

Validate before calling

// rust: pre-validate the fixture before constructing the client
let json: serde_json::Value = serde_json::from_slice(&std::fs::read(&path)?)?;
assert!(json["tokens"]["access_token"].is_string(), "fixture missing access_token");
assert!(json["tokens"]["account_id"].is_string(), "fixture missing account_id");

Try / catch

let client = CodewhaleClient::new(&config)
    .unwrap_or_else(|e| panic!("Codex client construction failed: {e:?}"));

Prevention

When it happens

Trigger: `CodewhaleClient::new` returns Err in the test after OPENAI_CODEX_AUTH_FILE points at a fixture auth.json whose access_token fails JWT/base64 validation, whose required fields are missing, or when the rustls crypto provider is not installed.

Common situations: Editing the fixture JSON into an invalid shape, test env var leakage between tests (lock_test_env not held), expired/malformed hand-written JWTs, or rustls default provider contention with other tests.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/1dd50f6afc2847fa. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/client.rs:8288

            providers: Some(ProvidersConfig {
                openai_codex: ProviderConfig {
                    auth_mode: Some("oauth".to_string()),
                    external_credentials: Some(
                        codewhale_config::ExternalCredentialConsentToml::read_only(
                            codewhale_config::ProviderKind::OpenaiCodex,
                            codewhale_config::ExternalCredentialSource::CodexCli,
                            path.clone(),
                        ),
                    ),
                    ..ProviderConfig::default()
                },
                ..ProvidersConfig::default()
            }),
            ..Config::default()
        };

        crate::external_credentials::reset_side_effect_trap();
        let client = CodewhaleClient::new(&config).expect("Codex client");
        assert_eq!(client.api_key, token_a);
        assert_eq!(client.codex_account_id.as_deref(), Some("account-a"));
        assert_eq!(
            crate::external_credentials::side_effect_trap_counts(),
            (1, 1),
            "bearer and account id must come from one secure open/read"
        );

        // An owner rotation after construction cannot splice account B into
        // the already-resolved bearer snapshot.
        std::fs::write(
            &path,
            serde_json::to_string(&serde_json::json!({"tokens": {"access_token": crate::test_support::future_test_jwt("b"), "account_id": "account-b"}})).expect("serialize rotated fixture"),
        )
        .expect("rotate fixture");
        assert_eq!(client.api_key, token_a);
        assert_eq!(client.codex_account_id.as_deref(), Some("account-a"));
    }

View on GitHub (pinned to 73e0f67d83)