{"record":{"id":"f6e780d713fd28e8","repo":"microsoft/garnet","slug":"err-bit-offset-is-not-an-integer-or-out-of-range","errorCode":null,"errorMessage":"ERR bit offset is not an integer or out of range","messagePattern":"ERR bit offset is not an integer or out of range","errorType":"validation","errorClass":"GarnetException","httpStatus":null,"severity":"error","filePath":"libs/server/Storage/Functions/MainStore/PrivateMethods.cs","lineNumber":871,"sourceCode":"            var cmd = RespCommand.NONE;\n            var sbCmd = input.parseState.GetArgSliceByRef(currTokenIdx++).ReadOnlySpan;\n            if (sbCmd.EqualsUpperCaseSpanIgnoringCase(CmdStrings.GET))\n                cmd = RespCommand.GET;\n            else if (sbCmd.EqualsUpperCaseSpanIgnoringCase(CmdStrings.SET))\n                cmd = RespCommand.SET;\n            else if (sbCmd.EqualsUpperCaseSpanIgnoringCase(CmdStrings.INCRBY))\n                cmd = RespCommand.INCRBY;\n\n            var bitfieldEncodingParsed = input.parseState.TryGetBitfieldEncoding(\n                                                currTokenIdx++, out var bitCount, out var isSigned);\n            Debug.Assert(bitfieldEncodingParsed);\n            var sign = isSigned ? (byte)BitFieldSign.SIGNED : (byte)BitFieldSign.UNSIGNED;\n\n            // Calculate number offset from bitCount if offsetArg starts with #\n            var offsetParsed = input.parseState.TryGetBitfieldOffset(currTokenIdx++, out var offset, out var multiplyOffset);\n            Debug.Assert(offsetParsed);\n            if (!BitmapManager.TryValidateBitfieldOffset(offset, (byte)bitCount, multiplyOffset, out offset, out _))\n                throw new GarnetException(\"ERR bit offset is not an integer or out of range\");\n\n            long value = default;\n            if (cmd == RespCommand.SET || cmd == RespCommand.INCRBY)\n            {\n                value = input.parseState.GetLong(currTokenIdx++);\n            }\n\n            var overflowType = (byte)BitFieldOverflow.WRAP;\n            if (currTokenIdx < input.parseState.Count)\n            {\n                var overflowTypeParsed = input.parseState.TryGetBitFieldOverflow(currTokenIdx, out var overflowTypeValue);\n                Debug.Assert(overflowTypeParsed);\n                overflowType = (byte)overflowTypeValue;\n            }\n\n            // Number of bits in signed number\n            // At most 64 bits can fit into encoding info\n            var typeInfo = (byte)(sign | bitCount);","sourceCodeStart":853,"sourceCodeEnd":889,"githubUrl":"https://github.com/microsoft/garnet/blob/951b0fc6838721f89d102c2bbe1b914e8d39d700/libs/server/Storage/Functions/MainStore/PrivateMethods.cs#L853-L889","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Use a smaller absolute bit offset that keeps offset + bitCount - 1 within the maximum bitmap size.","If using the # multiplier syntax, reduce the multiplier so offset * bitCount does not overflow or exceed the bitmap limit.","Validate the offset client-side before issuing BITFIELD: ensure it is non-negative and that offset + bitWidth - 1 <= maxBitmapBits."],"exampleFix":"// before\nBITFIELD mykey SET u8 #9223372036854775807 200\n\n// after\nBITFIELD mykey SET u8 #1000000 200","handlingStrategy":"validation","validationCode":"// Client-side validation before BITFIELD\nlong maxBits = 512L * 1024 * 1024 * 8; // adjust to your max bitmap size\nif (useHashOffset)\n{\n    if (offset < 0 || offset > long.MaxValue / bitWidth)\n        throw new ArgumentException(\"Offset out of range\");\n    long endBit = offset * bitWidth + bitWidth - 1;\n    if (endBit > maxBits) throw new ArgumentException(\"Bit offset exceeds max bitmap size\");\n}\nelse\n{\n    if (offset < 0 || offset + bitWidth - 1 > maxBits)\n        throw new ArgumentException(\"Bit offset out of range\");\n}","typeGuard":null,"tryCatchPattern":"// Catch as part of RESP error handling\ntry { client.BitField(key, ops); }\ncatch (GarnetException ex) when (ex.Message.Contains(\"bit offset\"))\n{ /* return Redis-compatible error to client */ }","preventionTips":["Validate BITFIELD offsets client-side before sending the command.","Cap multiplier offsets (# syntax) to prevent overflow in offset * bitWidth.","Sanitize user input that feeds into BITFIELD offset calculations."],"tags":["bitmap","bitfield","redis-compatible","runtime","garnet"],"backgroundTag":null,"analyzedSha":"951b0fc6838721f89d102c2bbe1b914e8d39d700","analyzedAt":"2026-08-13T19:01:32.939Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}