{"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":null,"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/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/dsh_credentials.rs#L30-L66","documentation":"After splitting a credentials line on `:`, `parse_dsh_deepseek_api_key` validates that the key is a POSIX identifier (letters/digits/underscore, not starting with a digit). A key like `deepseek-key-1` or containing dashes, spaces, or symbols fails this check and aborts with the line number.","triggerScenarios":"A dsh credentials document whose `KEY:` uses dashes, spaces, dots, or other non-identifier characters — e.g. `API-KEY: ...` or `my key: ...`.","commonSituations":"Copy-pasted keys from docs or other tools using dashed env-style names; hand-written files with spaces in key names; keys generated by another tool with a different naming convention.","solutions":["Rename the key on the reported line to a POSIX identifier (e.g. `API-KEY` → `API_KEY`).","Strip spaces and special characters from the key; use letters, digits, and underscores only, starting with a letter or underscore.","Compare against a known-good dsh credentials file to confirm the expected key names."],"exampleFix":"// before\nAPI-KEY: sk-abc\n// after\nAPI_KEY: sk-abc","handlingStrategy":"validation","validationCode":"// pre-check keys are POSIX identifiers\nlet re = regex::Regex::new(\"^[A-Za-z_][A-Za-z0-9_]*$\").unwrap();\nfor (i, line) in text.lines().enumerate() {\n    if let Some((k, _)) = line.trim().split_once(':') {\n        assert!(re.is_match(k.trim()), \"line {} key not an identifier\", i + 1);\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use underscores, never dashes or spaces, in credentials key names.","Start key names with a letter or underscore.","Validate key naming when generating credentials files programmatically."],"tags":["deepseek","credentials","identifier","validation"],"backgroundTag":"invalid-identifier","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"}