Fix Chunked Upload Request Timeout Failure - #236
Merged
Conversation
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>
marinofaggiana
self-requested a review
July 21, 2026 05:41
marinofaggiana
approved these changes
Jul 21, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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,uploadChunkAsyncderived 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
readFileOrFolderignoringoptions.timeouton the no-body PROPFIND path. Adds unit tests.🤖 AI (if applicable)