{"record":{"id":"bf6da0cd16b8fd30","repo":"gchq/CyberChef","slug":"offset-has-to-be-a-positive-integer","errorCode":null,"errorMessage":"Offset has to be a positive integer","messagePattern":"Offset has to be a positive integer","errorType":"validation","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/operations/RailFenceCipherDecode.mjs","lineNumber":58,"sourceCode":"\n    /**\n     * @param {string} input\n     * @param {Object[]} args\n     * @returns {string}\n     */\n    run(input, args) {\n        const [key, offset] = args;\n\n        const cipher = input;\n\n        if (key < 2) {\n            throw new OperationError(\"Key has to be bigger than 2\");\n        } else if (key > cipher.length) {\n            throw new OperationError(\"Key should be smaller than the cipher's length\");\n        }\n\n        if (offset < 0) {\n            throw new OperationError(\"Offset has to be a positive integer\");\n        }\n\n        const cycle = (key - 1) * 2;\n        const plaintext = new Array(cipher.length);\n\n        let j = 0;\n        let x, y;\n\n        for (y = 0; y < key; y++) {\n            for (x = 0; x < cipher.length; x++) {\n                if ((y + x + offset) % cycle === 0 || (y - x - offset) % cycle === 0) {\n                    plaintext[x] = cipher[j++];\n                }\n            }\n        }\n\n        return plaintext.join(\"\");\n    }","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/operations/RailFenceCipherDecode.mjs#L40-L76","documentation":"Thrown by RailFenceCipherDecode when the 'offset' argument is negative. Offset shifts where the zigzag pattern starts and must be a non-negative integer.","triggerScenarios":"Entering a negative offset; a recipe/config that supplies -1 or a computed negative value.","commonSituations":"Typo/sign error; importing a recipe whose offset defaulted to a negative; mismatching offset between encode and decode.","solutions":["Set offset to 0 or a positive integer.","Ensure the offset matches the value used during encoding.","Coerce the input: offset = Math.max(0, offset)."],"exampleFix":"// before\n//   offset: -2\n// after\n//   offset: 0","handlingStrategy":"validation","validationCode":"if (!Number.isInteger(offset) || offset < 0) throw new Error('Offset must be a non-negative integer');","typeGuard":"const isOffset = o => Number.isInteger(o) && o >= 0;","tryCatchPattern":"try { decode(input, { offset }); } catch (e) { if (/Offset/.test(e.message)) offset = Math.max(0, offset); else throw e; }","preventionTips":["Clamp offset with Math.max(0, offset).","Use the same offset used to encode."],"tags":["cipher","rail-fence","validation"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}