8000 [BUG] Chunked DBFS uploads overwrite files despite overwrite=false · Issue #35 · dmux/minilake · GitHub
[go: up one dir, main page]

Skip to content

[BUG] Chunked DBFS uploads overwrite files despite overwrite=false #35

Closed

Description

@eddiethedean

Description

Two upload sessions opened for the same absent path with overwrite=false can both close successfully; the later close destroys the earlier upload.

Reproduced on MiniLake 1.9.0, commit fe8837dcfac9df621dfabc440abc07ebb4cdbcbb, using the repository's Docker test image, a real HTTP server, and fresh disposable state. Image Python sources were verified byte-for-byte against this commit. No mocks or production data were used.

Affected Components

Steps to Reproduce

Use a disposable instance and data directory. Paths below are relative to its HTTP base URL; bodies are JSON unless explicitly described as raw bytes. IDs shown as W/J/R/Q/C/HANDLE are replaced with the IDs returned by prior calls.

  1. POST /api/2.0/dbfs/create twice with {"path":"/race","overwrite":false}, retaining handles A and B.
  2. POST /api/2.0/dbfs/add-block with {"handle":A,"data":"Zmlyc3Q="}, then /close with {"handle":A}.
  3. Add {"handle":B,"data":"c2Vjb25k"}, then close B.
  4. Read /race and base64-decode the result. This interleaving is reproducible sequentially; no timing race is necessary.

Expected Behavior

Closing B fails without replacing the file created by A, or opening B is rejected because the path is already reserved.

Actual Behavior

Both closes return 200; /race contains second, overwriting first.

Root Cause Analysis

The overwrite policy is checked only when opening the handle. close_handle stores but never reads entry["overwrite"], then unconditionally calls write_bytes.

Impact

Interleaved uploads and uploads overlapping a single-shot put can silently lose files despite explicit no-overwrite requests.

Severity is assessed within MiniLake's documented local development/CI use; it does not assume a shared production Databricks deployment.

Suggested Fix

Enforce no-overwrite at final commit using exclusive creation or an atomic no-replace operation. Retain recoverable upload state if commit fails.

Test Coverage Gaps

Chunked-upload tests use one handle with overwrite=true. Add two overlapping handles, an intervening put, and a failed close preserving the existing bytes.

Severity

High

Confidence

High — reproduced through the real HTTP API and traced to the source paths above.

Recommended Labels

bug, high-priority

Existing Issue Matches

No reasonable duplicate found. Reviewed all open and closed issues and open pull requests in dmux/minilake, then searched component/function/symptom terms for this finding. The only open PR at review time, #29, changes the virtualenv lock entry and does not address this defect. The documented intentional limitations were checked before reporting.

Activity

  1. eddiethedean commented on Oct 25, 2026

    @eddiethedean
    CollaboratorAuthor

    Additional scenario now verified through real HTTP on MiniLake 1.9.0 (DuckDB 1.5.6, Python 3.14.3): the competing writer can be the single-shot put endpoint; two chunked handles are unnecessary.

    1. POST /api/2.0/dbfs/create with {"path":"/late_upload","overwrite":false}; retain handle H.
    2. POST /api/2.0/dbfs/put for /late_upload with base64 content encoding created after handle; this succeeds because the path is still absent.
    3. Add base64-encoded late upload to H and close H.
    4. Read /late_upload: it contains late upload; the single-shot writer's file has been silently replaced.

    All steps were sequential, with no timing-dependent race. Add a cross-endpoint regression test and enforce no-replace semantics atomically at handle finalization, preserving both the existing destination and recoverable upload state when close fails.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      0