jstedfast/MailKit · error · ArgumentOutOfRangeException
outputOffset
Error message
outputOffset
What it means
TransformBlock throws ArgumentOutOfRangeException named "outputOffset" when an outputBuffer is supplied and outputOffset is negative or greater than outputBuffer.Length - inputCount. Because TransformBlock copies inputCount bytes into outputBuffer at outputOffset, the destination region must fit entirely inside the output array.
Solutions
- Allocate outputBuffer at least inputCount bytes and pass outputOffset 0 when hashing-only.
- Validate: 0 <= outputOffset && outputOffset <= outputBuffer.Length - inputCount before the call.
- If no copy-back is needed, pass null for outputBuffer — the check is skipped entirely.
- Recompute per-block output offsets (advance by inputCount each iteration).
Example fix
// before transform.TransformBlock(input, 0, input.Length, output, outPos); // outPos + input.Length > output.Length // after int outPos = 0; transform.TransformBlock(input, 0, input.Length, output, outPos); outPos += input.Length;
Defensive patterns
Strategy: validation
Validate before calling
if (outputBuffer != null && (outputOffset < 0 || outputOffset > outputBuffer.Length - inputCount))
throw new ArgumentOutOfRangeException(nameof(outputOffset)); Type guard
static bool IsValidOutput(byte[] output, int outputOffset, int inputCount) =>
output == null || (outputOffset >= 0 && outputOffset <= output.Length - inputCount); Try / catch
try { transform.TransformBlock(input, 0, inputCount, output, outputOffset); }
catch (ArgumentOutOfRangeException ex) when (ex.ParamName == "outputOffset") { log.LogError(ex, "Output window [{Off},{Count}] exceeds len {Len}", outputOffset, inputCount, output.Length); throw; } Prevention
- Pass null outputBuffer when you only need hashing, not copy-back
- Size output buffers to at least the block size
- Track outputOffset by advancing inputCount per block
When it happens
Trigger: Calling TransformBlock(input, 0, inputCount, output, badOffset) where badOffset + inputCount > output.Length — e.g. reusing an output offset accumulated across blocks without accounting for inputCount, or an output buffer smaller than the input block.
Common situations: Using TransformBlock as an echo/copy transform (the ICryptoTransform contract) with a mis-sized scratch buffer; ported code assuming outputOffset is always 0 while passing leftover offsets; output buffer allocated for a different block size.
Related errors
AI-assisted analysis of jstedfast/MailKit@9d3859a785 (2026-09-15).
Data as JSON: /api/errors/3f3c632d447d37fc.
Report an issue: GitHub.
Appendix: source
Thrown at MailKit/Security/Ntlm/MD4.cs:352
Initialize ();
return hashValue;
}
public int TransformBlock (byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
if (inputBuffer == null)
throw new ArgumentNullException (nameof (inputBuffer));
if (inputOffset < 0 || inputOffset > inputBuffer.Length)
throw new ArgumentOutOfRangeException (nameof (inputOffset));
if (inputCount < 0 || inputOffset > inputBuffer.Length - inputCount)
throw new ArgumentOutOfRangeException (nameof (inputCount));
if (outputBuffer != null) {
if (outputOffset < 0 || outputOffset > outputBuffer.Length - inputCount)
throw new ArgumentOutOfRangeException (nameof (outputOffset));
}
HashCore (inputBuffer, inputOffset, inputCount);
if (outputBuffer != null)
Buffer.BlockCopy (inputBuffer, inputOffset, outputBuffer, outputOffset, inputCount);
return inputCount;
}
public byte[] TransformFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount)
{
if (inputCount < 0)
throw new ArgumentOutOfRangeException (nameof (inputCount));
var outputBuffer = new byte[inputCount];
// note: other exceptions are handled by Buffer.BlockCopyView on GitHub (pinned to 9d3859a785)