{"record":{"id":"b19486848ef7200c","repo":"Hmbown/CodeWhale","slug":"deepseek-harness-credentials-line-has-an-empty","errorCode":null,"errorMessage":"DeepSeek Harness credentials line {} has an empty value","messagePattern":"DeepSeek Harness credentials line (.+?) has an empty value","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/dsh_credentials.rs","lineNumber":63,"sourceCode":"        };\n        let key = key.trim();\n        if !is_posix_identifier(key) {\n            bail!(\n                \"DeepSeek Harness credentials line {} has a non-identifier key\",\n                index + 1\n            );\n        }\n        if !seen.insert(key.to_string()) {\n            bail!(\"DeepSeek Harness credentials declare `{key}` more than once\");\n        }\n        let value = unquote_yaml_string(value.trim()).map_err(|reason| {\n            anyhow::anyhow!(\n                \"DeepSeek Harness credentials line {} is invalid: {reason}\",\n                index + 1\n            )\n        })?;\n        if value.is_empty() {\n            bail!(\n                \"DeepSeek Harness credentials line {} has an empty value\",\n                index + 1\n            );\n        }\n        if key == DEEPSEEK_API_KEY_REF {\n            found = Some(value);\n        }\n    }\n    Ok(found)\n}\n\nfn is_posix_identifier(value: &str) -> bool {\n    let mut chars = value.chars();\n    matches!(chars.next(), Some('A'..='Z' | 'a'..='z' | '_'))\n        && chars.all(|ch| matches!(ch, 'A'..='Z' | 'a'..='z' | '0'..='9' | '_'))\n}\n\nfn unquote_yaml_string(value: &str) -> Result<String, &'static str> {","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/dsh_credentials.rs#L45-L81","documentation":"parse_dsh_deepseek_api_key parses the dsh CLI's `.credentials.yaml` as a strict mapping of POSIX identifiers to non-empty quoted/plain strings. Any line of the form `KEY:` (or `KEY: \"\"`) with an empty value fails closed, because the parser refuses to treat an empty string as a credential. This guards against silently importing a blank DeepSeek API key.","triggerScenarios":"Calling `deepseek_api_key_from_grant` on a granted `$DSH_HOME/.credentials.yaml` that contains a non-comment, non-blank line whose value after the colon is empty (e.g. `DEEPSEEK_API_KEY:` or `DEEPSEEK_API_KEY: \"\"`).","commonSituations":"The dsh CLI was run but authentication never completed, so it wrote the key with an empty placeholder value; the user manually edited the credentials file and cleared the value; a provisioning script wrote an env-style file with the value to be filled in later.","solutions":["Run `dsh` login/auth to populate DEEPSEEK_API_KEY with a real key, then retry the Codewhale import.","Open the credentials file reported in the error and fill in the empty value on the indicated line number (1-indexed).","If you do not want dsh import, set DEEPSEEK_API_KEY directly via Codewhale's own config/auth path instead of the external-consent grant.","Remove the malformed line entirely if the key is not needed — blank lines and `#` comments are skipped."],"exampleFix":"// before: $DSH_HOME/.credentials.yaml\nDEEPSEEK_API_KEY:\n// after\nDEEPSEEK_API_KEY: \"sk-...actual-key...\"","handlingStrategy":"validation","validationCode":"// Pre-check the dsh credentials text before import\nfn has_empty_credential_value(text: &str) -> Option<usize> {\n    text.lines().enumerate().find_map(|(i, raw)| {\n        let line = raw.trim();\n        if line.is_empty() || line.starts_with('#') { return None; }\n        let value = line.split_once(':')?.1.trim();\n        (value.is_empty() || value == \"\\\"\\\"\").then(|| i + 1)\n    })\n}","typeGuard":null,"tryCatchPattern":"match deepseek_api_key_from_grant(&grant) {\n    Ok(Some(key)) if !key.is_empty() => use(key),\n    Ok(_) => println!(\"no DEEPSEEK_API_KEY in dsh credentials\"),\n    Err(e) if e.to_string().contains(\"empty value\") => eprintln!(\"run `dsh auth` to set the key: {e}\"),\n    Err(e) => return Err(e),\n}","preventionTips":["Run `dsh` auth and confirm the key is populated before enabling external-consent import.","Never hand-edit `.credentials.yaml` to placeholder/empty values.","Validate the YAML mapping non-destructively before granting read consent."],"tags":["credentials","yaml-parsing","deepseek","fail-closed"],"backgroundTag":"empty-required-field","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}