Skip to content

Fix Chunked Upload Request Timeout Failure - #236

Merged
marinofaggiana merged 3 commits into
mainfrom
i2h3/upload-timeout-failure
Jul 21, 2026
Merged

Fix Chunked Upload Request Timeout Failure#236
marinofaggiana merged 3 commits into
mainfrom
i2h3/upload-timeout-failure

Conversation

@i2h3

@i2h3 i2h3 commented Jul 20, 2026

Copy link
Copy Markdown
Collaborator

A customer support case depends on this.

Large chunked uploads could fail with errorChunkMoveFile (-9997) and an empty ocId even though the file assembled fine on the server: after the assembly MOVE, uploadChunkAsync derived the ocId only from a follow-up PROPFIND read-back, and threw -9997 whenever that hop failed (finalization lag / proxy 5xx / timeout).

This reads OC-FileID/OC-ETag/Date directly from the MOVE response — as the server returns them and the C++ NG client already relies on — and only falls back to a read-back (now with its own timeout + bounded retry) when the header is absent. Also fixes readFileOrFolder ignoring options.timeout on the no-body PROPFIND path. Adds unit tests.

🤖 AI (if applicable)

  • The content of this PR was partly or fully generated using AI

i2h3 and others added 2 commits July 17, 2026 15:17
Add an optional `ifMatch` parameter to `uploadChunkAsync`. When set, the
ETag precondition is applied ONLY to the final assembly MOVE that
materializes the destination file — never to the chunk PUTs, which target
brand-new chunk resources and would spuriously fail with 412. It is also
cleared before the post-assembly PROPFIND readback, whose target carries a
fresh ETag after a successful MOVE.

This lets clients perform optimistic-concurrency conflict detection for
chunked (large-file) uploads: if the destination changed since the base
version the client edited, the server rejects the assembly with 412
Precondition Failed instead of silently overwriting the newer copy.
Single-request PUT uploads can already carry `If-Match` via
`NKRequestOptions.customHeader`; this closes the gap for the chunked path,
where the shared header bag would otherwise leak the precondition onto the
chunk PUTs.

Signed-off-by: Iva Horn <iva.horn@nextcloud.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Large chunked uploads intermittently failed with errorChunkMoveFile (-9997,
"Move file error") and an empty ocId, even though the file had assembled
correctly on the server.

The name is misleading: uploadChunkAsync did not fail on the assembly MOVE.
After a successful MOVE it obtained the resulting NKFile solely from a
follow-up depth-0 PROPFIND read-back, which is the only source of the ocId on
the chunked path. When that read-back failed or returned no files — server-side
finalization lag, a proxy 5xx, or a timeout, all more likely for large files —
it threw errorChunkMoveFile and the ocId came back nil. Compounding this,
readFileOrFolder applied options.timeout only on the custom-body path, so the
no-body read-back silently ran with the URLSession default timeout instead of
the intended value.

Fix:
- Prefer the assembled file's identity straight from the MOVE response headers
  (OC-FileID, OC-ETag/ETag, Date) via a new assembledFile(fromMoveResponseHeaders:)
  helper, mirroring createFolder and the desktop C++ NG client, which reads and
  requires these headers off the same reply. This avoids the fragile second
  request entirely in the common case.
- Fall back to the PROPFIND read-back only when OC-FileID is absent (older
  server, a proxy that strips it, or a 202 async assembly), now with its own
  120s timeout and a bounded backoff retry; surface errorChunkMoveFile only
  after the retries are exhausted.
- Apply options.timeout on the no-body PROPFIND path in readFileOrFolder,
  matching every other WebDAV method.

Adds ChunkedUploadAssemblyTests covering the header derivation.

Signed-off-by: Iva Horn <iva.horn@nextcloud.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@i2h3 i2h3 self-assigned this Jul 20, 2026
@i2h3 i2h3 added 3. to review Waiting for reviews bug Something isn't working high High priority labels Jul 20, 2026
@github-project-automation github-project-automation Bot moved this to 🧭 Planning evaluation (don't pick) in 💻 Desktop Clients team Jul 20, 2026
@i2h3 i2h3 moved this from 🧭 Planning evaluation (don't pick) to 🏗️ In progress in 💻 Desktop Clients team Jul 20, 2026
@i2h3 i2h3 changed the title I2h3/upload timeout failure Fix Chunked Upload Request Timeout Failure Jul 20, 2026
@i2h3 i2h3 added this to the 7.4.0 milestone Jul 20, 2026
@i2h3 i2h3 removed their assignment Jul 20, 2026
@marinofaggiana
marinofaggiana self-requested a review July 21, 2026 05:41
@marinofaggiana
marinofaggiana merged commit 71fe462 into main Jul 21, 2026
4 checks passed
@github-project-automation github-project-automation Bot moved this from 🏗️ In progress to ☑️ Done in 💻 Desktop Clients team Jul 21, 2026
@i2h3
i2h3 deleted the i2h3/upload-timeout-failure branch July 21, 2026 09:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

3. to review Waiting for reviews bug Something isn't working high High priority

Projects

Status: ☑️ Done

Development

Successfully merging this pull request may close these issues.

2 participants