{"record":{"id":"9a90b3ca5cfe5ccc","repo":"gchq/CyberChef","slug":"offset-cannot-be-negative","errorCode":null,"errorMessage":"Offset cannot be negative","messagePattern":"Offset cannot be negative","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/operations/Bombe.mjs","lineNumber":138,"sourceCode":"        for (let i=0; i<4; i++) {\n            if (i === 0 && model === \"3-rotor\") {\n                // No fourth rotor\n                continue;\n            }\n            let rstr = args[i + 1];\n            // The Bombe doesn't take stepping into account so we'll just ignore it here\n            if (rstr.includes(\"<\")) {\n                rstr = rstr.split(\"<\", 2)[0];\n            }\n            rotors.push(rstr);\n        }\n        // Rotors are handled in reverse\n        rotors.reverse();\n        if (crib.length === 0) {\n            throw new OperationError(\"Crib cannot be empty\");\n        }\n        if (offset < 0) {\n            throw new OperationError(\"Offset cannot be negative\");\n        }\n        // For symmetry with the Enigma op, for the input we'll just remove all invalid characters\n        input = input.replace(/[^A-Za-z]/g, \"\").toUpperCase();\n        crib = crib.replace(/[^A-Za-z]/g, \"\").toUpperCase();\n        const ciphertext = input.slice(offset);\n        const reflector = new Reflector(reflectorstr);\n        let update;\n        if (isWorkerEnvironment()) {\n            update = this.updateStatus;\n        } else {\n            update = undefined;\n        }\n        const bombe = new BombeMachine(rotors, reflector, ciphertext, crib, check, update);\n        const result = bombe.run();\n        return {\n            nLoops: bombe.nLoops,\n            result: result\n        };","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/operations/Bombe.mjs#L120-L156","documentation":"The Bombe searches for the crib starting at a given offset into the ciphertext. A negative offset would slice the string from the wrong position, so the operation rejects it before processing.","triggerScenarios":"Calling Bombe.run with a negative offset argument (offset < 0).","commonSituations":"Off-by-one in UI arithmetic; user typed a minus sign; default value misconfigured to -1.","solutions":["Set offset to 0 or a positive integer not exceeding the ciphertext length.","Clamp offset in the UI to >= 0.","Verify the offset plus crib length does not exceed the input length."],"exampleFix":"// before\noffset = -1\n// after\noffset = 0","handlingStrategy":"validation","validationCode":"if (!Number.isInteger(offset) || offset < 0) throw new Error('Offset must be a non-negative integer');","typeGuard":"function isValidOffset(n) { return Number.isInteger(n) && n >= 0; }","tryCatchPattern":null,"preventionTips":["Clamp offset to >= 0 in the UI.","Ensure offset + crib.length <= input.length.","Default the offset field to 0."],"tags":["cipher","bombe","validation","offset"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}