{"record":{"id":"d354ff7198023a33","repo":"Hmbown/CodeWhale","slug":"fleet-alert-secret-name-is-not-configured","errorCode":null,"errorMessage":"fleet alert secret {name} is not configured","messagePattern":"fleet alert secret (.+?) is not configured","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/fleet/alerts.rs","lineNumber":489,"sourceCode":"        FleetAlertEventClass::VerifierFailed => \"verifier_failed\",\n        FleetAlertEventClass::RunCompleted => \"run_completed\",\n    }\n}\n\nfn redacted_secret_header(secret_env: Option<&str>) -> Value {\n    match secret_env {\n        Some(name) => json!({ \"X-CodeWhale-Webhook-Secret\": redacted_env(name) }),\n        None => json!({}),\n    }\n}\n\nfn required_secret<R>(resolver: &R, name: &str) -> Result<String>\nwhere\n    R: FleetAlertSecretResolver,\n{\n    resolver\n        .resolve(name)\n        .ok_or_else(|| anyhow!(\"fleet alert secret {name} is not configured\"))\n}\n\nfn required_https_url<R>(resolver: &R, name: &str) -> Result<String>\nwhere\n    R: FleetAlertSecretResolver,\n{\n    let url = resolver\n        .resolve(name)\n        .ok_or_else(|| anyhow!(\"fleet alert URL {name} is not configured\"))?;\n    validate_https_alert_url(name, &url)?;\n    Ok(url)\n}\n\nfn validate_https_alert_url(name: &str, url: &str) -> Result<()> {\n    let parsed = reqwest::Url::parse(url)\n        .with_context(|| format!(\"fleet alert URL from {name} is not a valid URL\"))?;\n    if parsed.scheme() != \"https\" {\n        return Err(anyhow!(\"fleet alert URL from {name} must use https\"));","sourceCodeStart":471,"sourceCodeEnd":507,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/tui/src/fleet/alerts.rs#L471-L507","documentation":"Alert adapters resolve secrets by name through a `FleetAlertSecretResolver`; the default `FleetEnvSecretResolver` reads `std::env::var(name)` and treats empty strings as unset (fleet/alerts.rs:86-90). `required_secret` errors when resolve returns None — the named secret (e.g. a webhook signing token) simply is not configured in the dispatching process.","triggerScenarios":"The env var named by adapter config is unset or empty where the dispatcher runs; the secret name in config is misspelled; the secret exists in a dev shell but not in the service or CI environment.","commonSituations":"Deploying without provisioning alert secrets; CI lacking env vars; name drift between adapter config and provisioning.","solutions":["Export the named variable with a non-empty value in the environment that dispatches alerts","Fix the secret name in adapter config to match the provisioned variable","Smoke-test resolution (present and non-empty) before enabling live dispatch; iterate with dry_run"],"exampleFix":"# before: FLEET_WEBHOOK_SECRET unset where the dispatcher runs\n# after (provision in that environment)\nexport FLEET_WEBHOOK_SECRET='...'\nsystemctl restart codewhale-fleet","handlingStrategy":"validation","validationCode":"fn secret_ready(name: &str) -> bool {\n    std::env::var(name).map(|v| !v.is_empty()).unwrap_or(false)\n}\nanyhow::ensure!(\n    secret_ready(&adapter.secret_env),\n    \"set {} before dispatching alerts\",\n    adapter.secret_env\n);","typeGuard":"fn secret_ready(name: &str) -> bool {\n    std::env::var(name).map(|v| !v.is_empty()).unwrap_or(false)\n}","tryCatchPattern":null,"preventionTips":["Provision alert secrets in every environment that dispatches (service, CI)","Fail fast on missing secrets at startup rather than at the first alert","Generate secret names for config and provisioning from one source of truth"],"tags":["alerts","fleet","secrets","configuration","environment"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}