Hmbown/CodeWhale · error

client with secret sentinels

Error message

client with secret sentinels

What it means

A panic from `CodewhaleClient::new(Config{...}).expect("client with secret sentinels")` in the helper `client_with_config_secret_sentinels` (crates/tui/src/client.rs). This helper builds a client from an inline Config carrying secret sentinel values (no auth file), so failure means the in-config credential path itself was rejected — invalid provider config, missing fields, or TLS/crypto setup failure.

Solutions

  1. Compare the helper's Config literal against the current Config/ProvidersConfig defaults after any struct field changes and fill new required fields.
  2. Confirm the rustls crypto provider install line is present and tolerant of double-install (let _ = ...install_default()).
  3. Read the Err payload by temporarily replacing expect with unwrap_or_else(|e| panic!("{e:?}")) to see which field was rejected.
  4. Run the consuming test singly (--test-threads=1) to rule out provider/env contention.

Example fix

// before
CodewhaleClient::new(Config { providers: ..., ..Config::default() }).expect("client with secret sentinels")
// after
CodewhaleClient::new(Config { providers: ..., ..Config::default() })
    .unwrap_or_else(|e| panic!("client with secret sentinels: {e:?}"))
Defensive patterns

Strategy: validation

Validate before calling

// rust: sanity-check the sentinel config before construction
assert!(!config.provider.as_deref().unwrap_or_default().is_empty(), "provider unset");
let _ = rustls::crypto::ring::default_provider().install_default();

Try / catch

CodewhaleClient::new(config).unwrap_or_else(|e| panic!("sentinel client: {e:?}"))

Prevention

When it happens

Trigger: Calling `client_with_config_secret_sentinels()` from tests like model_bound_request_repairs_dangling_tool_call_before_adapter_projection when Config{provider, providers...} fails validation inside CodewhaleClient::new, or when the rustls ring provider cannot be installed.

Common situations: Changes to Config/ProvidersConfig/ProviderConfig required fields after a refactor leave the helper's literal incomplete; rustls provider install racing across parallel tests; API-key validation tightened upstream.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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

Appendix: source

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

                    ..ProviderConfig::default()
                },
                xiaomi_mimo: ProviderConfig {
                    api_key: Some(CONFIG_SECRET_SENTINELS[5].to_string()),
                    ..ProviderConfig::default()
                },
                zai: ProviderConfig {
                    api_key: Some(CONFIG_SECRET_SENTINELS[6].to_string()),
                    ..ProviderConfig::default()
                },
                sakana: ProviderConfig {
                    api_key: Some(CONFIG_SECRET_SENTINELS[7].to_string()),
                    ..ProviderConfig::default()
                },
                ..ProvidersConfig::default()
            }),
            ..Config::default()
        })
        .expect("client with secret sentinels")
    }

    fn request_with_tool_result(content: impl Into<String>) -> MessageRequest {
        MessageRequest {
            model: "glm-5.2".to_string(),
            messages: vec![
                Message {
                    role: Role::Assistant,
                    content: vec![ContentBlock::ToolUse {
                        id: "call-secret-test".to_string(),
                        name: "read_file".to_string(),
                        input: json!({"path": "config.toml"}),
                        caller: None,
                        thought_signature: None,
                    }],
                },
                Message {
                    role: Role::User,

View on GitHub (pinned to 73e0f67d83)