Skip to content

fix(upload): preserve resume offset, survive pod restart, reject chunk gaps#350

Merged
lovehunter9 merged 1 commit into
mainfrom
fix/larepass_upload
Jun 15, 2026
Merged

fix(upload): preserve resume offset, survive pod restart, reject chunk gaps#350
lovehunter9 merged 1 commit into
mainfrom
fix/larepass_upload

Conversation

@lovehunter9

Copy link
Copy Markdown
Collaborator

Summary

Three small, independent fixes to the chunked upload state machine that together stop a class of resume bugs (cursor stuck, finalize ENOENT, "completed" but truncated file):

  • SaveFile drops O_APPEND on the resume path. POSIX forces every write to EOF when O_APPEND is set, which silently nullified the explicit Seek(offset, SeekStart) below it: any chunk that did not start exactly at the temp file's tail (e.g. a half-written chunk left by a network drop or page refresh) ended up appended to EOF instead of overwriting at the requested offset, accumulating drift until the final chunk hit the early-return at info.Offset > offsetEnd and the response was rejected as success but unmarshal-mismatched (500).
  • HandleUploadChunks only purges the on-disk temp/.info on chunk 1. Mid-stream retries that arrive after a pod restart find an empty in-memory InfoSyncMap; previously this branch unconditionally deleted the on-disk temp file, after which subsequent chunks no longer matched any SaveFile condition and were silently skipped, leaving the final chunk's MoveFileByInfo to fail with no such file or directory.
  • Reject chunks that jump past the server's current offset. When a client mixes a fresh chunk 1 (which truncates the temp via newFile=true) with mid-stream chunk N requests still in flight, the gap chunks fell through every SaveFile predicate and were quietly accepted as 200, so the final chunk's MoveFileByInfo finalized a truncated file as if the upload had succeeded. Such requests now return an explicit error so the client can react instead of finalizing bad data.

Test plan

  • Upload mid-size file, restart files-server pod mid-upload (do not refresh the page) → upload resumes and completes; final size matches source.
  • Upload mid-size file, refresh the page mid-upload → re-uploading the same file resumes from the server's uploadedBytes and completes; final size matches source.
  • Pod restart in the middle of a chunk write (force resumablejs to retry after server returns 5xx) → no no such file or directory on the final chunk.
  • Trigger the "chunk-gap" pathology (e.g. browser refresh after pod restart, then upload the same file): the upload now fails with an explicit error rather than reporting completed for a truncated file.
  • Existing happy paths (fresh upload, first-time chunked upload, chunk 1 to chunk N straight through) unaffected.

Made with Cursor

…k gaps

Co-authored-by: Cursor <cursoragent@cursor.com>
@lovehunter9 lovehunter9 force-pushed the fix/larepass_upload branch from 1cfd234 to 342bc96 Compare June 15, 2026 14:03
@lovehunter9 lovehunter9 merged commit b4b279e into main Jun 15, 2026
1 check passed
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.

1 participant