Skip to content

fix: sha256 verification to prevent corrupt partial download loop#1095

Merged
cjpais merged 8 commits intocjpais:mainfrom
VirenMohindra:vm/fix-partial-download-checksums
Mar 21, 2026
Merged

fix: sha256 verification to prevent corrupt partial download loop#1095
cjpais merged 8 commits intocjpais:mainfrom
VirenMohindra:vm/fix-partial-download-checksums

Conversation

@VirenMohindra
Copy link
Copy Markdown
Contributor

@VirenMohindra VirenMohindra commented Mar 19, 2026

Before Submitting This PR

  • I have searched existing issues and pull requests to ensure this isn't a duplicate
  • I have read CONTRIBUTING.md

Human Written Description

the partial download bug (#858) has been causing infinite loops for a long time — corrupt .partial files survive extraction failures and get resumed on next launch, trapping users with no way out except manually hunting down and deleting the file. i traced the root cause to commit 86a1205 where cancel_download() only flips a flag but doesn't cancel the in-flight request, leaving partial files on disk in unknown states.

sha256 checksums catch corruption regardless of cause (interrupted download, bad resume, anything), and hardcoding them next to each model's url means the fix is transparent and easy to maintain. also deletes .partial on extraction failure as a belt-and-suspenders fix for cases where checksums aren't available (e.g. future custom model support).

Related Issues/Discussions

Fixes #858
Related: #1015

Community Feedback

#858 has been open since feb 2026 with multiple users confirming the bug. this is a complete fix rather than the cleanup-on-failure approach in #1015.

Testing

  • fresh model download: verifies sha256 post-download, proceeds normally
  • corrupt .partial (simulated by truncating): hash mismatch → deletes partial → next launch starts fresh, no loop
  • extraction failure: .partial deleted, next attempt re-downloads cleanly
  • download failure: surfaces toast in both settings page and onboarding (previously silent in settings)

AI Assistance

  • AI was used (please describe below)

If AI was used:

  • Tools used: Claude Code
  • How extensively: pair programmed the full implementation — root cause investigation, library research, architecture decisions (hardcoded hashes vs manifest endpoint, sha256 vs etag), and code writing. all tradeoffs reviewed and approved by me.

@VirenMohindra VirenMohindra force-pushed the vm/fix-partial-download-checksums branch 3 times, most recently from c6bfaee to 95effff Compare March 19, 2026 07:24
Fixes issue cjpais#858 — corrupt .partial files caused an infinite loop where
a failed/cancelled download would resume from EOF, pass extraction, and
loop forever with no way to recover without manual file deletion.

Three-part fix:
- Add sha2 crate and compute_sha256() helper; verify hash post-download
  before extraction/rename for all 15 built-in models. Hash mismatch
  deletes the .partial so the next attempt starts fresh.
- Delete .partial on extraction failure (independent of checksums) so
  corrupt archives can't re-enter the loop via the same path.
- Emit model-download-failed event from the command handler so all
  callers (ModelsSettings, Onboarding) get consistent error feedback
  via a central store listener rather than per-caller return-value checks.

SHA256 hashes hardcoded alongside each model's URL in ModelInfo.
Custom models (sha256: None) skip verification silently.
Doc comments on exported specta types propagate into bindings.ts as
inline JSDoc — not useful in generated TS. Removing at the source.
Extracts inline verify logic into ModelManager::verify_sha256() and
covers all four branches:
- None expected hash → skipped (custom models)
- Matching hash → ok, file kept
- Mismatched hash → error returned, partial file deleted
- Unreadable file → error returned

Ensures corrupt partial downloads are always cleaned up so the next
attempt starts fresh.
…llback cleanup

- remove cancel_flags entry on sha256 failure to prevent a stale flag
  from immediately cancelling the next retry attempt (HIGH)
- add fallback state cleanup in modelStore when result.status != ok,
  so spinner clears even if model-download-failed event is missed (HIGH)
- run compute_sha256 in spawn_blocking to avoid stalling the async
  executor while hashing large model files (up to 1.6 GB) (MEDIUM)
@VirenMohindra VirenMohindra force-pushed the vm/fix-partial-download-checksums branch from 9abc539 to 6f676c7 Compare March 19, 2026 23:33
@VirenMohindra
Copy link
Copy Markdown
Contributor Author

would love any feedback and thoughts @sheeki03

DylanBricar added a commit to DylanBricar/Phonara that referenced this pull request Mar 20, 2026
- SHA256 download verification to prevent corrupt partial download loops (cjpais#1095)
- Secondary transcription shortcut with independent language setting (cjpais#1106)
- Double-click tray icon to show main window (cjpais#369)
- CLI --auto-submit flag to force enter after transcription (cjpais#1099)
- OCR template context via ${OCR} variable in post-processing prompts (cjpais#770)
@cjpais cjpais merged commit 58cda3f into cjpais:main Mar 21, 2026
4 checks passed
@VirenMohindra VirenMohindra deleted the vm/fix-partial-download-checksums branch March 21, 2026 15:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Partial downloads prevent the model from ever being downloaded again

2 participants