{"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":"validation","errorClass":null,"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/0924356b4caba4989607227b7c8824d3d8098719/src/hooks/integrity.rs#L172-L208","documentation":"After splitting, read_stored_hash validates that the extracted hash field is exactly 64 ASCII hex characters (a real SHA-256 digest). If it is shorter/longer or contains non-hex characters, the stored checksum is unusable and the function bails to prevent a trivially-true or broken integrity comparison.","triggerScenarios":"Calling verify_hook_at where the hash file contains a truncated hash, a placeholder like '<hash>', an md5 (32 hex chars) instead of sha256, or the filename was accidentally split into the hash field (single-space separator shifting fields).","commonSituations":"Regenerating checksums with `md5sum` instead of `sha256sum`; copy/paste truncating the digest; editing tools mangling the line; corruption of the checksum file on disk.","solutions":["Regenerate with SHA-256: `sha256sum <hook file> > <hook file>.sha256` from within the hooks directory","Verify the first field: `awk '{print length($1)}' <hook>.sha256` must print 64","Reinstall via rtk init so the checksum is written by rtk itself"],"exampleFix":"// before (md5, 32 chars)\nmd5sum rtk-rewrite.sh > rtk-rewrite.sh.sha256\n// after\n(cd ~/.claude/hooks && sha256sum rtk-rewrite.sh > rtk-rewrite.sh.sha256)","handlingStrategy":"validation","validationCode":"HASH=$(cut -d' ' -f1 \"$hook.sha256\"); [[ ${#HASH} -eq 64 && \"$HASH\" =~ ^[0-9a-fA-F]{64}$ ]] || sha256sum \"$hook\" > \"$hook.sha256\"","typeGuard":"fn is_sha256_hex(s: &str) -> bool {\n    s.len() == 64 && s.chars().all(|c| c.is_ascii_hexdigit())\n}","tryCatchPattern":"match read_stored_hash(&hash_path) {\n    Err(e) if e.to_string().contains(\"Invalid SHA-256\") => {\n        eprintln!(\"regenerating checksum for {}\", hash_path.display());\n        write_checksum(&hook_path)?;\n    }\n    other => other?,\n}","preventionTips":["Use sha256sum exclusively; md5 digests (32 hex) fail the length check","Never truncate or placeholder-edit digests when scripting","Reinstall hooks via rtk init rather than copying checksum files between machines"],"tags":["integrity","sha256","validation","hooks"],"backgroundTag":"checksum-mismatch","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"}