Skip to content

Concatenation operation is not idempotent, causing duplicate uploads on retried requests #1364

@ollie-sutton

Description

@ollie-sutton

Describe the bug
When a client sends a POST request with Upload-Concat: final;url1 url2 ..., the server creates a new upload, concatenates the partial uploads, and returns 201 Created. If something in the request chain kills the connection before the response reaches the client due to a long file concatenation time (e.g. a WAF timeout rule, proxy timeout, or network interruption), the client never receives the response and tusd never emits the finished events/hooks. On retry, the server creates a new final upload with a new random ID and performs the concatenation again, wasting storage and triggering duplicate processing via hooks.

To Reproduce

  1. Upload two partial uploads (Upload-Concat: partial)
  2. Send a POST with Upload-Concat: final;/files/a /files/b
  3. Kill the connection before the 201 Created response is delivered to the client (e.g. via a WAF timeout rule or proxy timeout)
  4. Retry the same POST with Upload-Concat: final;/files/a /files/b
  5. Observe that a second, duplicate final upload is created and concatenation runs again

Expected behavior
The concat operation should be idempotent. When the same set of partial uploads is presented for concatenation a second time, the server should detect that a final upload already exists for those partials and:

  • If concatenation already completed (offset == size): return the existing final upload
  • If the upload was created but concatenation didn't start (offset == 0): retry the concatenation on the existing upload
  • Not create a duplicate final upload

Setup details

  • Used tusd version: v2.9.2
  • Used tusd data storage: Disk storage using a PVC within K8s
  • Used tus client library: node tus client

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions