Skip to content

TUS upload: Inconsistent HTTP status codes (404 vs 409) when re-uploading to completed session in K8s #11854

@anon-pradip

Description

@anon-pradip

Description:

Summary

When attempting to upload the last chunk twice to the same TUS upload session, the behavior differs between Docker and Kubernetes deployments:

  • Docker CI: Consistently returns 404 Not Found
  • K8s CI: Returns either 404 Not Found or 409 Conflict (non-deterministic)

Environment

Hypothesis

The issue appears to be related to OCIS_ASYNC_UPLOADS: true in K8s deployment:

  • When async uploads are enabled, upload session cleanup happens asynchronously
  • Re-uploading immediately after completion creates a race condition:
    • If cleanup is still in progress → 409 Conflict
    • If cleanup completed → 404 Not Found
  • Docker CI might use synchronous uploads, resulting in consistent 404 responses

Steps to Reproduce

  1. Deploy oCIS in Kubernetes (k3d)
  2. Create a TUS upload session
  3. Upload all chunks to complete the upload
  4. Immediately attempt to upload the last chunk again to the same session
  5. Observe the HTTP status code

Expected Behavior

Consistent HTTP status code across all deployment types (Docker, K8s, etc.)

Actual Behavior

  • Docker: Always returns 404 Not Found
  • K8s: Returns 404 Not Found OR 409 Conflict (race condition suspected)

Test Case

Failing CI: https://drone.owncloud.com/owncloud/ocis/49540/15/8

  Scenario Outline: send last chunk twice                                                                                   # /drone/src/tests/acceptance/features/coreApiWebdavUploadTUS/lowLevelUpload.feature:45
    Given using <dav-path-version> DAV path                                                                                 # FeatureContext::usingOldOrNewOrSpacesDavPath()
    And user "Alice" has created a new TUS resource on the WebDAV API with these headers:                                   # TUSContext::userHasCreatedNewTUSResourceWithHeaders()
      | Upload-Length   | 10                    |
      | Upload-Metadata | filename ZmlsZS50eHQ= |
    When user "Alice" sends a chunk to the last created TUS Location with offset "0" and data "123" using the WebDAV API    # TUSContext::userSendsAChunkToTUSLocationWithOffsetAndData()
    And user "Alice" sends a chunk to the last created TUS Location with offset "3" and data "4567890" using the WebDAV API # TUSContext::userSendsAChunkToTUSLocationWithOffsetAndData()
    And user "Alice" sends a chunk to the last created TUS Location with offset "3" and data "0000000" using the WebDAV API # TUSContext::userSendsAChunkToTUSLocationWithOffsetAndData()
    Then the HTTP status code should be "404"                                                                               # FeatureContext::thenTheHTTPStatusCodeShouldBe()
    And the content of file "/file.txt" for user "Alice" should be "1234567890"                                             # FeatureContext::contentOfFileForUserShouldBe()
    Examples:
      | dav-path-version |
      | old              |
        Failed step: Then the HTTP status code should be "404"
        HTTP status code 409 is not the expected value 404
        Failed asserting that 409 matches expected '404'.
      | new              |
        Failed step: Then the HTTP status code should be "404"
        HTTP status code 409 is not the expected value 404
        Failed asserting that 409 matches expected '404'.
      | spaces           |
        Failed step: Then the HTTP status code should be "404"
        HTTP status code 409 is not the expected value 404
        Failed asserting that 409 matches expected '404'.

The test expects 404 when re-uploading to a completed session, but K8s sometimes returns 409.

Current Workaround
Modified test: #11826 to accept both 404 and 409 as valid responses:


What is the correct/expected HTTP status code when re-uploading to a completed TUS session, and why does K8s behave differently than Docker?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions