{"record":{"id":"4587f6f2f8786fe4","repo":"rtk-ai/rtk","slug":"invalid-sha-256-hash-in","errorCode":null,"errorMessage":"Invalid SHA-256 hash in {}","messagePattern":"Invalid SHA-256 hash in (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/hooks/integrity.rs","lineNumber":190,"sourceCode":"        .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\n/// Run integrity check and print results (for `rtk verify` subcommand)\npub fn run_verify(verbose: u8) -> Result<()> {\n    let result = report_hook_status(verbose);\n    report_data_dir_privacy();\n    result\n}\n\nfn report_hook_status(verbose: u8) -> Result<()> {","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/rtk-ai/rtk/blob/d977e1c31621fe8704e6500ceeb9c7a0de2b6836/src/hooks/integrity.rs#L172-L208","documentation":"After the two-space split succeeds, the first field must be exactly 64 ASCII hex characters (a SHA-256 digest). This bail means the digest itself is wrong: typically an md5/sha1 digest (32/40 chars), a truncated hash, or placeholder text sitting in the hash slot of the .sha256 sidecar.","triggerScenarios":"Hash file produced with `md5sum`/`sha1sum`, a templating variable that never expanded, or manual edits — caught at src/hooks/integrity.rs:192 during `rtk verify`.","commonSituations":"Scripts defaulting to md5; LLM-generated dotfiles containing a placeholder hash; copy-paste that dropped characters.","solutions":["Regenerate with sha256sum: `sha256sum <hook path> > <hook path>.sha256`","Or re-run `rtk init -g` to have rtk rewrite the hook and its stored hash together","If you intentionally modified the hook script, prefer re-init over hand-editing the hash so the later content comparison stays meaningful"],"exampleFix":"# before: md5 digest (32 hex chars) in the hash slot\n5d41402a...  rtk-rewrite.sh\n\n# after\nsha256sum ~/.claude/hooks/rtk-rewrite.sh > ~/.claude/hooks/rtk-rewrite.sh.sha256","handlingStrategy":"validation","validationCode":"# bash: assert the digest is 64 hex chars (not md5/sha1)\nhead -1 \"$SHA\" | grep -qE '^[0-9a-fA-F]{64}  ' || { echo 'not a SHA-256 digest' >&2; exit 2; }","typeGuard":"// Rust: narrow to a 64-hex SHA-256 digest field\nfn is_sha256_digest(field: &str) -> bool {\n    field.len() == 64 && field.chars().all(|c| c.is_ascii_hexdigit())\n}","tryCatchPattern":null,"preventionTips":["Standardize hash generation on sha256sum in all scripts","Treat a wrong-length digest as a red flag for the generating pipeline, not just a bad file","Let rtk manage its own integrity files via re-init instead of editing them"],"tags":["integrity","sha256","verify","hash"],"backgroundTag":null,"analyzedSha":"d977e1c31621fe8704e6500ceeb9c7a0de2b6836","analyzedAt":"2026-08-16T05:40:46.291Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}