{"record":{"id":"6e00f70e828d116a","repo":"Hmbown/CodeWhale","slug":"deepseek-harness-credentials-line-has-a-non-ide","errorCode":null,"errorMessage":"DeepSeek Harness credentials line {} has a non-identifier key","messagePattern":"DeepSeek Harness credentials line (.+?) has a non-identifier key","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/dsh_credentials.rs","lineNumber":48,"sourceCode":"/// non-empty strings. Nested values, empty strings, and duplicate keys fail\n/// closed. Only `DEEPSEEK_API_KEY` is returned.\npub(crate) fn parse_dsh_deepseek_api_key(text: &str) -> Result<Option<String>> {\n    let mut found = None;\n    let mut seen = std::collections::BTreeSet::new();\n    for (index, raw) in text.lines().enumerate() {\n        let line = raw.trim();\n        if line.is_empty() || line.starts_with('#') {\n            continue;\n        }\n        let Some((key, value)) = line.split_once(':') else {\n            bail!(\n                \"DeepSeek Harness credentials line {} is not `KEY: value`\",\n                index + 1\n            );\n        };\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            );","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/dsh_credentials.rs#L30-L66","documentation":"Thrown by parse_dsh_deepseek_api_key when the key before the colon, after trimming, is not a POSIX identifier (per is_posix_identifier: [A-Za-z_][A-Za-z0-9_]*). Keys with dashes, spaces, dots, or leading digits fail closed; the error names the 1-based line number.","triggerScenarios":"Lines like \"api-key: v\" (dash), \"DEEPSEEK API_KEY: v\" (space), \"2KEY: v\" (leading digit), or \"DEEPSEEK.API_KEY: v\" (dot).","commonSituations":"Renaming keys to kebab-case by habit; generated files using non-identifier key names; merge artifacts introducing malformed keys.","solutions":["Rename the key to a POSIX identifier: letters, digits, underscore, not starting with a digit","Use underscore separation, e.g. DEEPSEEK_API_KEY, not kebab-case","Comment out lines you do not need instead of leaving malformed ones"],"exampleFix":"# before\napi-key: some-value\n\n# after\napi_key: some-value","handlingStrategy":"validation","validationCode":"fn is_posix_identifier(value: &str) -> bool {\n    let mut chars = value.chars();\n    matches!(chars.next(), Some('a'..='z' | 'A'..='Z' | '_'))\n        && chars.all(|c| matches!(c, 'a'..='z' | 'A'..='Z' | '0'..='9' | '_'))\n}\n\n// Validate keys before import:\nfor (index, line) in text.lines().enumerate() {\n    let line = line.trim();\n    if line.is_empty() || line.starts_with('#') { continue; }\n    let key = line.split_once(':').context(\"missing colon\")?.0.trim();\n    if !is_posix_identifier(key) {\n        return Err(anyhow::anyhow!(\"line {}: key {key:?} is not a POSIX identifier\", index + 1));\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Stick to UPPER_SNAKE_CASE keys like DEEPSEEK_API_KEY","Avoid dashes, dots, and spaces in keys; never start a key with a digit","Let an editor's spell-check/linter flag odd key names before import"],"tags":["rust","tui","credentials","parse-error","identifier","deepseek"],"backgroundTag":"credentials-file-parse-error","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}