{"record":{"id":"0b87500e4afa9aad","repo":"duplicati/duplicati","slug":"handlewriteerror","errorCode":"HandleWriteError","errorMessage":"Failed to write to file, difference between bytes read and bytes written","messagePattern":"Failed to write to file, difference between bytes read and bytes written","errorType":"exception","errorClass":"UserInformationException","httpStatus":null,"severity":"error","filePath":"Duplicati/Library/Backend/SMB/SMBShareConnection.cs","lineNumber":483,"sourceCode":"            }).ConfigureAwait(false);\n\n            if (status == NTStatus.STATUS_SUCCESS)\n            {\n                // Use the provided write buffer size if set, otherwise use the protocol negotiated maximum. Never exceed the negotiated maximum.\n                var buffer = new byte[Math.Min(_connectionParameters.WriteBufferSize ?? (int)_smb2Client.MaxWriteSize, _smb2Client.MaxWriteSize)];\n                int bytesRead;\n                int numberOfBytesWritten;\n                int offset = 0;\n                using var timeoutStream = sourceStream.ObserveReadTimeout(_timeouts.ReadWriteTimeout, false);\n                while (!cancellationToken.IsCancellationRequested && timeoutStream.Position < timeoutStream.Length)\n                {\n                    bytesRead = await timeoutStream.ReadAsync(buffer, cancellationToken);\n                    if (bytesRead == 0)\n                        break;\n                    status = _smbFileStore.WriteFile(out numberOfBytesWritten, fileHandle, offset, buffer.Take(bytesRead).ToArray());\n                    offset += numberOfBytesWritten;\n                    if (numberOfBytesWritten != bytesRead)\n                        throw new UserInformationException(LC.L(\"Failed to write to file, difference between bytes read and bytes written\"), \"HandleWriteError\");\n                    if (status != NTStatus.STATUS_SUCCESS)\n                        throw new UserInformationException($\"{LC.L(\"Failed to write file on Putasync\")} {filename} with status {status.ToString()}\", \"HandleWriteError\");\n                }\n                if (fileHandle != null)\n                {\n                    status = _smbFileStore.CloseFile(fileHandle);\n                    if (status != NTStatus.STATUS_SUCCESS)\n                        throw new UserInformationException($\"{LC.L(\"Failed to close file handle on PutAsync\")} {filename} with status {status.ToString()}\", \"HandleCloseError\");\n                }\n            }\n            else\n            {\n                throw new UserInformationException($\"{LC.L(\"Failed to create file for writing\")} {filename} with status {status.ToString()}\", \"FileCreateError\");\n            }\n        }\n        finally\n        {\n            _semaphore.Release();","sourceCodeStart":465,"sourceCodeEnd":501,"githubUrl":"https://github.com/duplicati/duplicati/blob/3f348be3e33f5d72d414e3ad55839c2ba34dda67/Duplicati/Library/Backend/SMB/SMBShareConnection.cs#L465-L501","documentation":"Thrown inside SMBShareConnection.PutAsync during the chunked file-upload loop. After calling _smbFileStore.WriteFile, the code checks that numberOfBytesWritten equals bytesRead for that chunk. SMB servers can report fewer bytes written than the chunk submitted (a partial write), which this guard treats as a hard failure rather than silently corrupting the uploaded file. The error code is 'HandleWriteError'.","triggerScenarios":"Calling PutAsync on the SMB backend; the WriteFile call succeeds (STATUS_SUCCESS) but returns a numberOfBytesWritten smaller than the bytesRead passed to it for a given buffer chunk. This typically happens with mismatched buffer sizes, connection instability, or a server that limits the accepted write size per call.","commonSituations":"WriteBufferSize exceeds what the negotiated SMB MaxWriteSize allows; transient network issues causing the server to partially accept a chunk; connecting to a Samba or Windows share with an older dialect that caps per-write byte counts; the buffer is sized larger than the server's negotiated maximum.","solutions":["Check the server-side SMB logs for the specific chunk that was partially accepted; reduce the configured WriteBufferSize to stay within the negotiated maximum.","Verify network stability between the Duplicati host and the SMB share (packet loss, MTU fragmentation, VPN MTU clamp).","Update to the latest Duplicati version; this guard exists to detect a protocol-level partial write that earlier builds may have silently ignored.","If targeting Samba, ensure the server version supports SMB 2.0.2+ and that the negotiated dialect matches the client expectations."],"exampleFix":"// before: buffer may exceed negotiated max, server accepts partial chunk\nvar buffer = new byte[Math.Min(_connectionParameters.WriteBufferSize ?? (int)_smb2Client.MaxWriteSize, _smb2Client.MaxWriteSize)];\n\n// after: clamp explicitly and loop the remainder if server reports fewer bytes\nvar chunkSize = Math.Min(_connectionParameters.WriteBufferSize ?? (int)_smb2Client.MaxWriteSize, _smb2Client.MaxWriteSize);\n// handle partial writes by re-sending the unwritten tail instead of throwing","handlingStrategy":"validation","validationCode":"// Before calling PutAsync, verify the configured write buffer size does not exceed the negotiated maximum\nvar configuredWriteSize = connectionParameters.WriteBufferSize ?? (int)smb2Client.MaxWriteSize;\nif (configuredWriteSize > smb2Client.MaxWriteSize)\n    throw new InvalidOperationException($\"WriteBufferSize {configuredWriteSize} exceeds negotiated max {smb2Client.MaxWriteSize}\");","typeGuard":null,"tryCatchPattern":"try\n{\n    await smbBackend.PutAsync(filename, stream, cancellationToken);\n}\ncatch (UserInformationException ex) when (ex.HelpID == \"HandleWriteError\")\n{\n    // Partial write detected; the file may be incomplete on the share\n    logger.LogWarning(\"SMB partial write for {File}: {Message}\", filename, ex.Message);\n    throw; // or retry with a smaller buffer\n}","preventionTips":["Keep WriteBufferSize within the SMB negotiated MaxWriteSize.","Monitor network stability between the Duplicati host and the SMB share.","Test uploads with smaller files first to detect buffer/protocol mismatches early."],"tags":["smb","network","file-upload","partial-write"],"backgroundTag":null,"analyzedSha":"3f348be3e33f5d72d414e3ad55839c2ba34dda67","analyzedAt":"2026-08-13T16:48:27.008Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}