duplicati/duplicati · error · UserInformationException
HandleWriteError
HandleWriteError
Error message
Failed to write to file, difference between bytes read and bytes written
What it means
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'.
Source
Thrown at Duplicati/Library/Backend/SMB/SMBShareConnection.cs:483
}).ConfigureAwait(false);
if (status == NTStatus.STATUS_SUCCESS)
{
// Use the provided write buffer size if set, otherwise use the protocol negotiated maximum. Never exceed the negotiated maximum.
var buffer = new byte[Math.Min(_connectionParameters.WriteBufferSize ?? (int)_smb2Client.MaxWriteSize, _smb2Client.MaxWriteSize)];
int bytesRead;
int numberOfBytesWritten;
int offset = 0;
using var timeoutStream = sourceStream.ObserveReadTimeout(_timeouts.ReadWriteTimeout, false);
while (!cancellationToken.IsCancellationRequested && timeoutStream.Position < timeoutStream.Length)
{
bytesRead = await timeoutStream.ReadAsync(buffer, cancellationToken);
if (bytesRead == 0)
break;
status = _smbFileStore.WriteFile(out numberOfBytesWritten, fileHandle, offset, buffer.Take(bytesRead).ToArray());
offset += numberOfBytesWritten;
if (numberOfBytesWritten != bytesRead)
throw new UserInformationException(LC.L("Failed to write to file, difference between bytes read and bytes written"), "HandleWriteError");
if (status != NTStatus.STATUS_SUCCESS)
throw new UserInformationException($"{LC.L("Failed to write file on Putasync")} {filename} with status {status.ToString()}", "HandleWriteError");
}
if (fileHandle != null)
{
status = _smbFileStore.CloseFile(fileHandle);
if (status != NTStatus.STATUS_SUCCESS)
throw new UserInformationException($"{LC.L("Failed to close file handle on PutAsync")} {filename} with status {status.ToString()}", "HandleCloseError");
}
}
else
{
throw new UserInformationException($"{LC.L("Failed to create file for writing")} {filename} with status {status.ToString()}", "FileCreateError");
}
}
finally
{
_semaphore.Release();View on GitHub (pinned to 3f348be3e3)
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.
Example fix
// before: buffer may exceed negotiated max, server accepts partial chunk var buffer = new byte[Math.Min(_connectionParameters.WriteBufferSize ?? (int)_smb2Client.MaxWriteSize, _smb2Client.MaxWriteSize)]; // after: clamp explicitly and loop the remainder if server reports fewer bytes var chunkSize = Math.Min(_connectionParameters.WriteBufferSize ?? (int)_smb2Client.MaxWriteSize, _smb2Client.MaxWriteSize); // handle partial writes by re-sending the unwritten tail instead of throwing
Defensive patterns
Strategy: validation
Validate before calling
// Before calling PutAsync, verify the configured write buffer size does not exceed the negotiated maximum
var configuredWriteSize = connectionParameters.WriteBufferSize ?? (int)smb2Client.MaxWriteSize;
if (configuredWriteSize > smb2Client.MaxWriteSize)
throw new InvalidOperationException($"WriteBufferSize {configuredWriteSize} exceeds negotiated max {smb2Client.MaxWriteSize}"); Try / catch
try
{
await smbBackend.PutAsync(filename, stream, cancellationToken);
}
catch (UserInformationException ex) when (ex.HelpID == "HandleWriteError")
{
// Partial write detected; the file may be incomplete on the share
logger.LogWarning("SMB partial write for {File}: {Message}", filename, ex.Message);
throw; // or retry with a smaller buffer
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- ConnectionError
- FileCreateError
- RenameFileError
- Invalid file size {0}, expected {1} for {2}
- BackblazeErrorResponse
AI-assisted analysis of duplicati/duplicati@3f348be3e3 (2026-08-13).
Data as JSON: /api/errors/0b87500e4afa9aad.
Report an issue: GitHub.