microsoft/garnet · error · GarnetException

ERR bit offset is not an integer or out of range

Error message

ERR bit offset is not an integer or out of range

What it means

During BITFIELD command processing in the main store, Garnet validates the bit offset. TryValidateBitfieldOffset fails when: bitCount is 0, the offset is negative, the offset multiplication (for # syntax) overflows int64, the end offset (offset + bitCount - 1) overflows, or the end offset exceeds the maximum bitmap size. This mirrors Redis's 'ERR bit offset is not an integer or out of range' behavior.

Source

Thrown at libs/server/Storage/Functions/MainStore/PrivateMethods.cs:871

            var cmd = RespCommand.NONE;
            var sbCmd = input.parseState.GetArgSliceByRef(currTokenIdx++).ReadOnlySpan;
            if (sbCmd.EqualsUpperCaseSpanIgnoringCase(CmdStrings.GET))
                cmd = RespCommand.GET;
            else if (sbCmd.EqualsUpperCaseSpanIgnoringCase(CmdStrings.SET))
                cmd = RespCommand.SET;
            else if (sbCmd.EqualsUpperCaseSpanIgnoringCase(CmdStrings.INCRBY))
                cmd = RespCommand.INCRBY;

            var bitfieldEncodingParsed = input.parseState.TryGetBitfieldEncoding(
                                                currTokenIdx++, out var bitCount, out var isSigned);
            Debug.Assert(bitfieldEncodingParsed);
            var sign = isSigned ? (byte)BitFieldSign.SIGNED : (byte)BitFieldSign.UNSIGNED;

            // Calculate number offset from bitCount if offsetArg starts with #
            var offsetParsed = input.parseState.TryGetBitfieldOffset(currTokenIdx++, out var offset, out var multiplyOffset);
            Debug.Assert(offsetParsed);
            if (!BitmapManager.TryValidateBitfieldOffset(offset, (byte)bitCount, multiplyOffset, out offset, out _))
                throw new GarnetException("ERR bit offset is not an integer or out of range");

            long value = default;
            if (cmd == RespCommand.SET || cmd == RespCommand.INCRBY)
            {
                value = input.parseState.GetLong(currTokenIdx++);
            }

            var overflowType = (byte)BitFieldOverflow.WRAP;
            if (currTokenIdx < input.parseState.Count)
            {
                var overflowTypeParsed = input.parseState.TryGetBitFieldOverflow(currTokenIdx, out var overflowTypeValue);
                Debug.Assert(overflowTypeParsed);
                overflowType = (byte)overflowTypeValue;
            }

            // Number of bits in signed number
            // At most 64 bits can fit into encoding info
            var typeInfo = (byte)(sign | bitCount);

View on GitHub (pinned to 951b0fc683)

Solutions

  1. Use a smaller absolute bit offset that keeps offset + bitCount - 1 within the maximum bitmap size.
  2. If using the # multiplier syntax, reduce the multiplier so offset * bitCount does not overflow or exceed the bitmap limit.
  3. Validate the offset client-side before issuing BITFIELD: ensure it is non-negative and that offset + bitWidth - 1 <= maxBitmapBits.

Example fix

// before
BITFIELD mykey SET u8 #9223372036854775807 200

// after
BITFIELD mykey SET u8 #1000000 200
Defensive patterns

Strategy: validation

Validate before calling

// Client-side validation before BITFIELD
long maxBits = 512L * 1024 * 1024 * 8; // adjust to your max bitmap size
if (useHashOffset)
{
    if (offset < 0 || offset > long.MaxValue / bitWidth)
        throw new ArgumentException("Offset out of range");
    long endBit = offset * bitWidth + bitWidth - 1;
    if (endBit > maxBits) throw new ArgumentException("Bit offset exceeds max bitmap size");
}
else
{
    if (offset < 0 || offset + bitWidth - 1 > maxBits)
        throw new ArgumentException("Bit offset out of range");
}

Try / catch

// Catch as part of RESP error handling
try { client.BitField(key, ops); }
catch (GarnetException ex) when (ex.Message.Contains("bit offset"))
{ /* return Redis-compatible error to client */ }

Prevention

When it happens

Trigger: BITFIELD key with: a #N offset where N * bitCount overflows int64 (e.g., '#9223372036854775807' with u8); a negative offset; or an absolute offset whose end bit exceeds MaxBitmapPayloadBits. Also BITFIELD SET/INCRBY where the computed end position is out of range.

Common situations: Client sending BITFIELD with computed offsets from untrusted input; scripts generating BITFIELD commands with large multiplier offsets; migrating data from another system with very large bitmap keys.

Related errors


AI-assisted analysis of microsoft/garnet@951b0fc683 (2026-08-13). Data as JSON: /api/errors/f6e780d713fd28e8. Report an issue: GitHub.