Hmbown/CodeWhale · error · anyhow::Error

DeepSeek Harness credentials line {} has a non-identifier ke

Error message

DeepSeek Harness credentials line {} has a non-identifier key

What it means

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.

Source

Thrown at crates/tui/src/dsh_credentials.rs:48

/// non-empty strings. Nested values, empty strings, and duplicate keys fail
/// closed. Only `DEEPSEEK_API_KEY` is returned.
pub(crate) fn parse_dsh_deepseek_api_key(text: &str) -> Result<Option<String>> {
    let mut found = None;
    let mut seen = std::collections::BTreeSet::new();
    for (index, raw) in text.lines().enumerate() {
        let line = raw.trim();
        if line.is_empty() || line.starts_with('#') {
            continue;
        }
        let Some((key, value)) = line.split_once(':') else {
            bail!(
                "DeepSeek Harness credentials line {} is not `KEY: value`",
                index + 1
            );
        };
        let key = key.trim();
        if !is_posix_identifier(key) {
            bail!(
                "DeepSeek Harness credentials line {} has a non-identifier key",
                index + 1
            );
        }
        if !seen.insert(key.to_string()) {
            bail!("DeepSeek Harness credentials declare `{key}` more than once");
        }
        let value = unquote_yaml_string(value.trim()).map_err(|reason| {
            anyhow::anyhow!(
                "DeepSeek Harness credentials line {} is invalid: {reason}",
                index + 1
            )
        })?;
        if value.is_empty() {
            bail!(
                "DeepSeek Harness credentials line {} has an empty value",
                index + 1
            );

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Rename the key to a POSIX identifier: letters, digits, underscore, not starting with a digit
  2. Use underscore separation, e.g. DEEPSEEK_API_KEY, not kebab-case
  3. Comment out lines you do not need instead of leaving malformed ones

Example fix

# before
api-key: some-value

# after
api_key: some-value
Defensive patterns

Strategy: validation

Validate before calling

fn is_posix_identifier(value: &str) -> bool {
    let mut chars = value.chars();
    matches!(chars.next(), Some('a'..='z' | 'A'..='Z' | '_'))
        && chars.all(|c| matches!(c, 'a'..='z' | 'A'..='Z' | '0'..='9' | '_'))
}

// Validate keys before import:
for (index, line) in text.lines().enumerate() {
    let line = line.trim();
    if line.is_empty() || line.starts_with('#') { continue; }
    let key = line.split_once(':').context("missing colon")?.0.trim();
    if !is_posix_identifier(key) {
        return Err(anyhow::anyhow!("line {}: key {key:?} is not a POSIX identifier", index + 1));
    }
}

Prevention

When it happens

Trigger: Lines like "api-key: v" (dash), "DEEPSEEK API_KEY: v" (space), "2KEY: v" (leading digit), or "DEEPSEEK.API_KEY: v" (dot).

Common situations: Renaming keys to kebab-case by habit; generated files using non-identifier key names; merge artifacts introducing malformed keys.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/6e00f70e828d116a. Report an issue: GitHub.