{"record":{"id":"94362b7702b2da19","repo":"gitbutlerapp/gitbutler","slug":"failed-to-initialize-signature-verifier-e","errorCode":null,"errorMessage":"Failed to initialize signature verifier: {e}","messagePattern":"Failed to initialize signature verifier: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/but-installer/src/install.rs","lineNumber":74,"sourceCode":"\n    // Write signature to temp file for minisign to parse\n    let signature_file = temp_dir.join(\"signature.minisig\");\n    fs::write(&signature_file, &signature_bytes)?;\n\n    // Read it back as a string (minisign signatures are text files)\n    let signature_str =\n        fs::read_to_string(&signature_file).context(\"Failed to read signature file as string\")?;\n\n    // Parse the signature\n    let signature =\n        minisign_verify::Signature::decode(&signature_str).context(\"Failed to parse signature\")?;\n\n    // Use streaming verification to avoid loading entire file into memory\n    let mut file =\n        File::open(installable).context(\"Failed to open installable for verification\")?;\n    let mut verifier = public_key\n        .verify_stream(&signature)\n        .map_err(|e| anyhow!(\"Failed to initialize signature verifier: {e}\"))?;\n\n    // Read and verify file in 64KB chunks\n    let mut buffer = [0u8; 65536];\n    loop {\n        let bytes_read = file.read(&mut buffer)?;\n        if bytes_read == 0 {\n            break;\n        }\n        verifier.update(&buffer[..bytes_read]);\n    }\n\n    // Finalize verification\n    verifier.finalize().map_err(|e| {\n        anyhow!(\"Signature verification failed - the download may have been tampered with: {e}\")\n    })?;\n\n    ui::info(\"Signature verification passed\");\n    Ok(())","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-installer/src/install.rs#L56-L92","documentation":"verify_signature() uses minisign (public_key.verify_stream) to initialize a streaming signature verifier for a downloaded artifact. The error wraps any failure from creating that verifier — meaning the signature data itself could not be accepted by the verifier (malformed/undecodable signature), not that content mismatched.","triggerScenarios":"Calling download_and_install_app (or the test_verify_signature_empty test path) where the base64 signature downloaded from the release server fails to decode or initialize in verify_stream — e.g. empty, truncated, or wrongly-encoded signature file.","commonSituations":"Old releases whose signature assets are missing or in a legacy format; a CDN/proxy returning an HTML error page instead of the .sig file; network truncation of the signature.","solutions":["Re-download; check the signature URL actually returns a valid base64 minisign signature (curl the .sig URL and inspect)","Confirm the release/channel version publishes signatures — older versions may not","Check that proxies/CDNs aren't substituting error pages for the .sig asset"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// sanity-check the signature payload before verification\nif sig_b64.trim().is_empty() {\n    anyhow::bail!(\"signature file is empty; refusing to verify\");\n}\nlet decoded = base64::decode(sig_b64.trim())?;\nanyhow::ensure!(decoded.starts_with(b\"untrusted comment:\"), \"not a minisign signature\");","typeGuard":null,"tryCatchPattern":"if let Err(e) = verify_signature(&file, &sig, &dir) {\n    if e.to_string().contains(\"initialize signature verifier\") {\n        eprintln!(\"Signature asset invalid — re-download or use a newer release\");\n    }\n    return Err(e);\n}","preventionTips":["Fetch signatures only from the official release domain (validate_download_url)","Never verify against an empty or HTML-body response; check content-type","Prefer releases known to publish signatures for all assets"],"tags":["signature","security","minisign","download"],"backgroundTag":"checksum-mismatch","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}