{"record":{"id":"98f80228eb82baeb","repo":"rtk-ai/rtk","slug":"invalid-hash-format-in-expected-hash-filenam","errorCode":null,"errorMessage":"Invalid hash format in {} (expected 'hash  filename')","messagePattern":"Invalid hash format in (.+?) \\(expected 'hash  filename'\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/hooks/integrity.rs","lineNumber":182,"sourceCode":"}\n\n/// Read the stored hash from the hash file.\n///\n/// Expects exact `sha256sum -c` format: `<64 hex>  <filename>\\n`\n/// Rejects malformed files rather than silently accepting them.\nfn read_stored_hash(path: &Path) -> Result<String> {\n    let content = fs::read_to_string(path)\n        .with_context(|| format!(\"Failed to read hash file: {}\", path.display()))?;\n\n    let line = content\n        .lines()\n        .next()\n        .with_context(|| format!(\"Empty hash file: {}\", path.display()))?;\n\n    // sha256sum format uses two-space separator: \"<hash>  <filename>\"\n    let parts: Vec<&str> = line.splitn(2, \"  \").collect();\n    if parts.len() != 2 {\n        anyhow::bail!(\n            \"Invalid hash format in {} (expected 'hash  filename')\",\n            path.display()\n        );\n    }\n\n    let hash = parts[0];\n    if hash.len() != 64 || !hash.chars().all(|c| c.is_ascii_hexdigit()) {\n        anyhow::bail!(\"Invalid SHA-256 hash in {}\", path.display());\n    }\n\n    Ok(hash.to_string())\n}\n\n/// Resolve the default hook path (~/.claude/hooks/rtk-rewrite.sh)\npub fn resolve_hook_path() -> Result<PathBuf> {\n    resolve_claude_dir().map(|dir| dir.join(HOOKS_SUBDIR).join(REWRITE_HOOK_FILE))\n}\n","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/rtk-ai/rtk/blob/0924356b4caba4989607227b7c8824d3d8098719/src/hooks/integrity.rs#L164-L200","documentation":"read_stored_hash parses a sha256sum-format checksum file: it expects a single line of '<hash>  <filename>' separated by exactly two spaces. If splitting the first line on the two-space separator does not yield exactly 2 parts, the file's format is not what rtk wrote, and it bails so verification fails safely rather than comparing garbage.","triggerScenarios":"Calling verify_hook_at on a hook whose .sha256 file was hand-edited, truncated, generated with a single-space separator (`sha256sum file > f` piped differently), or written by another tool with a different line layout; also when the file contains extra lines/whitespace such that splitn(2, \"  \") yields != 2 parts.","commonSituations":"Manually regenerating checksums with `shasum -a 256` variants that pad differently; editors stripping trailing spaces or normalizing double spaces; partial writes/corruption of the hash file in ~/.claude/hooks.","solutions":["Regenerate the hash file the way rtk expects: `cd <hook dir> && sha256sum rtk-rewrite.sh > rtk-rewrite.sh.sha256` (sha256sum emits the two-space separator)","Inspect the file: `cat -A <hook>.sha256` to see hidden spacing; fix it to '<64-hex>  <filename>' with exactly two spaces and a single line","Reinstall the hook via rtk (e.g. `rtk init -g`) so rtk rewrites the checksum file itself"],"exampleFix":"// before (hand-written, single space)\nabc123  rtk-rewrite.sh\n// after\nprintf '%s  %s\\n' \"$(sha256sum rtk-rewrite.sh | cut -d' ' -f1)\" \"rtk-rewrite.sh\" > rtk-rewrite.sh.sha256","handlingStrategy":"validation","validationCode":"// validate a sha256sum file before running verify\nawk 'NR==1 && split($0, a, \"  \") == 2 { exit (length(a[1])==64 && a[1] ~ /^[0-9a-fA-F]+$/) ? 0 : 1 }' \"$hook.sha256\" || regen_checksums","typeGuard":"fn is_sha256sum_line(line: &str) -> bool {\n    match line.splitn(2, \"  \").collect::<Vec<_>>()[..] {\n        [h, _f] => h.len() == 64 && h.chars().all(|c| c.is_ascii_hexdigit()),\n        _ => false,\n    }\n}","tryCatchPattern":"match verify_hook_at(&path) {\n    Err(e) if e.to_string().contains(\"Invalid hash format\") => regenerate_checksum_file(&path)?,\n    other => other?,\n}","preventionTips":["Only generate checksums with `sha256sum` (two-space separator), not `md5sum` or `shasum` defaults","Do not hand-edit .sha256 files; let `rtk init` write them","Audit with `cat -A` after editors touch hook directories (trailing-space stripping breaks the format)"],"tags":["integrity","sha256","file-format","hooks"],"backgroundTag":"invalid-argument-format","analyzedSha":"0924356b4caba4989607227b7c8824d3d8098719","analyzedAt":"2026-09-19T19:25:29.612Z","contentChangedAt":"2026-09-19T19:25:29.612Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}