Hmbown/CodeWhale · error

DeepSeek Harness credentials line

Error message

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

What it means

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.

Solutions

  1. Rename the key on the reported line to a POSIX identifier (e.g. `API-KEY` → `API_KEY`).
  2. Strip spaces and special characters from the key; use letters, digits, and underscores only, starting with a letter or underscore.
  3. Compare against a known-good dsh credentials file to confirm the expected key names.

Example fix

// before
API-KEY: sk-abc
// after
API_KEY: sk-abc
Defensive patterns

Strategy: validation

Validate before calling

// pre-check keys are POSIX identifiers
let re = regex::Regex::new("^[A-Za-z_][A-Za-z0-9_]*$").unwrap();
for (i, line) in text.lines().enumerate() {
    if let Some((k, _)) = line.trim().split_once(':') {
        assert!(re.is_match(k.trim()), "line {} key not an identifier", i + 1);
    }
}

Prevention

When it happens

Trigger: A dsh credentials document whose `KEY:` uses dashes, spaces, dots, or other non-identifier characters — e.g. `API-KEY: ...` or `my key: ...`.

Common situations: 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.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/6e00f70e828d116a. Report an issue: GitHub.

Appendix: 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 73e0f67d83)