{"record":{"id":"e8932b943b4d865b","repo":"zeroclaw-labs/zeroclaw","slug":"auth-secret-secret-name-is-empty-after-decrypt","errorCode":null,"errorMessage":"auth_secret '{secret_name}' is empty after decryption","messagePattern":"auth_secret '(.+?)' is empty after decryption","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-tools/src/http_request.rs","lineNumber":320,"sourceCode":"                \"Failed to parse config file {} for auth_secret '{secret_name}': {e}\",\n                config_path.display()\n            ))\n        })?;\n\n        let raw_secret = config\n            .http_request\n            .secrets\n            .get(secret_name)\n            .filter(|secret| !secret.is_empty())\n            .ok_or_else(|| anyhow::Error::msg(format!(\"auth_secret '{secret_name}' not found\")))?;\n\n        let secret = if zeroclaw_config::secrets::SecretStore::is_encrypted(raw_secret) {\n            let zeroclaw_dir = config_path.parent().unwrap_or_else(|| Path::new(\".\"));\n            let store =\n                zeroclaw_config::secrets::SecretStore::new(zeroclaw_dir, self.secrets_encrypt);\n            let plaintext = store.decrypt(raw_secret)?;\n            if plaintext.is_empty() {\n                anyhow::bail!(\"auth_secret '{secret_name}' is empty after decryption\");\n            }\n            plaintext\n        } else {\n            raw_secret.clone()\n        };\n\n        if let Some(env_secret) = resolve_env_backed_auth_secret(secret_name, &secret)? {\n            Ok(env_secret)\n        } else {\n            Ok(secret)\n        }\n    }\n\n    fn apply_auth_secret(\n        &self,\n        headers: &mut HeaderMap,\n        auth_secret: Option<&str>,\n    ) -> anyhow::Result<()> {","sourceCodeStart":302,"sourceCodeEnd":338,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-tools/src/http_request.rs#L302-L338","documentation":"Thrown by HttpRequestTool::reload_auth_secret (crates/zeroclaw-tools/src/http_request.rs:320) when a secret entry in [http_request.secrets] is recognized as encrypted (zeroclaw_config::secrets::SecretStore format), decrypts successfully, but yields an empty string. Decryption worked; the stored plaintext itself is empty. The tool refuses to send an empty Authorization header, because that would silently break auth.","triggerScenarios":"Running the secret-encrypt workflow while the source value was empty (e.g. exported an unset env var before encrypting); encrypting \"\" deliberately as a placeholder; a secret rotation script that encrypted an empty replacement; secrets_encrypt flag mismatches usually fail decryption with a different error, so this specifically means empty plaintext.","commonSituations":"Bootstrap scripts that encrypt ${VAR} when VAR was unset in that shell; CI pipelines creating placeholder secrets for new environments; copy-pasted encrypt commands run before the value was pasted in.","solutions":["Re-encrypt the secret with a non-empty plaintext using zeroclaw's SecretStore and update the config.toml entry.","Verify end-to-end: decrypt the stored value once after encryption and assert it is non-empty.","If the secret is intentionally env-backed, encrypt \"${VAR_NAME}\" (the reference string) rather than the current env contents."],"exampleFix":"# before\napi_token = \"<encrypted empty string>\"  # decrypts to \"\"\n\n# after\n# re-run: zeroclaw secret encrypt with the real value\napi_token = \"<encrypted 'Bearer real-token'>\"","handlingStrategy":"validation","validationCode":"// at startup, verify every configured secret decrypts to a non-empty value\nfor (name, raw) in &config.http_request.secrets {\n    if SecretStore::is_encrypted(raw) {\n        let plain = store.decrypt(raw)?;\n        anyhow::ensure!(!plain.is_empty(), \"secret '{name}' decrypts to empty\");\n    }\n}","typeGuard":null,"tryCatchPattern":"let result = tool.execute(args).await?;\nif let Some(err) = &result.error {\n    if err.contains(\"is empty after decryption\") {\n        // re-encrypt the secret with its real value, then retry\n    }\n}","preventionTips":["Run the encrypt workflow from a shell where the source value is verified non-empty.","Add a post-encryption decrypt assertion to secret-management scripts.","For env-sourced secrets, encrypt the \"${VAR}\" reference string, not the current env contents."],"tags":["http","auth","secrets","encryption","zeroclaw"],"backgroundTag":"empty-secret-after-decryption","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}