BeyondDimension/SteamTools · error · FormatException

Malformed input: {0} is an invalid input length.

Error message

Malformed input: {0} is an invalid input length.

What it means

Thrown by the base64 decoder's padding calculator when inputLength % 4 == 1. Valid base64 input length modulo 4 can only be 0, 2, or 3 (mapping to 0, 2, or 1 padding chars); a remainder of 1 is structurally impossible for correctly-encoded base64, so the input is malformed and cannot be decoded.

Source

Thrown at src/BD.WTTS.Client.Plugins.Update/WebEncoders.cs:186

        }

        var numPaddingCharsToAdd = GetNumBase64PaddingCharsToAddForDecode(count);

        return checked(count + numPaddingCharsToAdd);
    }

    private static int GetNumBase64PaddingCharsToAddForDecode(int inputLength)
    {
        switch (inputLength % 4)
        {
            case 0:
                return 0;
            case 2:
                return 2;
            case 3:
                return 1;
            default:
                throw new FormatException(
                    string.Format(
                        CultureInfo.CurrentCulture,
                        "Malformed input: {0} is an invalid input length.",
                        inputLength));
        }
    }
}

View on GitHub (pinned to c16ffa08e0)

Solutions

  1. Validate length % 4 != 1 before decoding and reject/repair the input with a clear message.
  2. Re-copy the full base64 string from source without truncation.
  3. Normalize URL-safe base64 ('-' -> '+', '_' -> '/') and re-add '=' padding before decoding.
  4. Strip whitespace/newlines consistently, then re-check the length.

Example fix

// before
var decoded = WebEncoders.Base64UrlDecode(input); // throws if input.Length % 4 == 1

// after: pre-validate length and re-pad
input = input.Replace('-', '+').Replace('_', '/').Trim();
switch (input.Length % 4)
{
    case 2: input += "=="; break;
    case 3: input += "="; break;
    case 1: throw new ArgumentException("Base64 input is malformed (length % 4 == 1).", nameof(input));
}
var decoded = WebEncoders.Base64UrlDecode(input);
Defensive patterns

Strategy: validation

Validate before calling

// Normalize and length-validate base64 input BEFORE decoding.
static string NormalizeBase64(string input)
{
    input = input.Trim().Replace('-', '+').Replace('_', '/');
    input = input.TrimEnd('=');
    var pad = input.Length % 4 switch
    {
        2 => "==",
        3 => "=",
        0 => "",
        _ => throw new ArgumentException($"Invalid base64 length {input.Length} (mod 4 == 1).", nameof(input))
    };
    return input + pad;
}

var decoded = WebEncoders.Base64UrlDecode(NormalizeBase64(input));

Type guard

bool IsValidBase64Length(string s) => s.Trim().Length % 4 != 1;

Try / catch

try { return WebEncoders.Base64UrlDecode(input); }
catch (FormatException ex) when (ex.Message.Contains("invalid input length"))
{
    // Re-copy from source, normalize URL-safe chars, then retry; otherwise reject the input.
    var normalized = NormalizeBase64(input);
    if (IsValidBase64Length(normalized)) return WebEncoders.Base64UrlDecode(normalized);
    throw new ArgumentException("Base64 input is malformed and cannot be recovered.", nameof(input), ex);
}

Prevention

When it happens

Trigger: Calling the WebEncoders base64 decode path with a string whose length mod 4 equals 1 — i.e. a character was lost/added, the string was truncated mid-group, or non-base64 characters were stripped leaving an invalid length.

Common situations: Truncated base64 (copy-paste cut off); URL-safe base64 with '-'/'_' not normalized back to '+'/'/' before length-sensitive decoding; whitespace/newlines stripped unevenly; a stray character inserted; mismatched encoder (e.g. hex mistaken for base64).

Understand the failure class

Related errors


AI-assisted analysis of BeyondDimension/SteamTools@c16ffa08e0 (2026-08-13). Data as JSON: /api/errors/c18d5be7290ce64e. Report an issue: GitHub.