{"record":{"id":"cf9f2124c79ad4dd","repo":"gchq/CyberChef","slug":"drop-every-must-be-a-positive-integer","errorCode":null,"errorMessage":"'Drop every' must be a positive integer.","messagePattern":"'Drop every' must be a positive integer\\.","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/operations/DropNthBytes.mjs","lineNumber":57,"sourceCode":"                name: \"Apply to each line\",\n                type: \"boolean\",\n                value: false\n            }\n        ];\n    }\n\n    /**\n     * @param {byteArray} input\n     * @param {Object[]} args\n     * @returns {byteArray}\n     */\n    run(input, args) {\n        const n = args[0];\n        const start = args[1];\n        const eachLine = args[2];\n\n        if (parseInt(n, 10) !== n || n <= 0) {\n            throw new OperationError(\"'Drop every' must be a positive integer.\");\n        }\n        if (parseInt(start, 10) !== start || start < 0) {\n            throw new OperationError(\"'Starting at' must be a positive or zero integer.\");\n        }\n\n        let offset = 0;\n        const output = [];\n        for (let i = 0; i < input.length; i++) {\n            if (eachLine && input[i] === 0x0a) {\n                output.push(0x0a);\n                offset = i + 1;\n            } else if (i - offset < start || (i - (start + offset)) % n !== 0) {\n                output.push(input[i]);\n            }\n        }\n\n        return output;\n    }","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/operations/DropNthBytes.mjs#L39-L75","documentation":"Thrown in DropNthBytes.run when the first argument n ('Drop every') fails parseInt(n,10) !== n || n <= 0. parseInt(n,10) !== n is the classic integer check (false for NaN and any non-integer). With n <= 0 it enforces a strictly positive integer. The arg defaults to 4, so this fires only for an out-of-range user or programmatic value.","triggerScenarios":"The 'Drop every' field receives 0, a negative number, a fraction like 2.5, NaN, or a non-numeric string. Common via imported recipe JSON with a bad value, a cleared UI field that coerces oddly, or the Node API passing an unguarded computed value.","commonSituations":"Hand-edited recipe JSON setting Drop every to 0 or a float; programmatic use passing a float multiplier; UI field left blank and coerced to 0.","solutions":["Set 'Drop every' to a whole number >= 1 (default 4).","If building the recipe programmatically, coerce with Math.max(1, Math.floor(n)) first.","Per AGENTS.md, move this constraint into the Ingredient args metadata (min value / integer) so validateIngredients() rejects it before run().","Validate imported recipe JSON before loading."],"exampleFix":"// before\nconst args = [0, 0, false];            // throws\n// after\nconst args = [Math.max(1, Math.floor(n)), 0, false];","handlingStrategy":"validation","validationCode":"function dropEvery(n) {\n  if (!Number.isInteger(n) || n <= 0) throw new RangeError(\"Drop every must be a positive integer\");\n  return n;\n}\nconst safeN = dropEvery(args[0]);","typeGuard":"const isPositiveInt = (v) => Number.isInteger(v) && v > 0;","tryCatchPattern":null,"preventionTips":["Coerce computed n with Math.max(1, Math.floor(n)) before passing.","Prefer declaring integer/min constraints in the Ingredient args metadata so validateIngredients() rejects bad values pre-run.","Validate imported recipe JSON before loading."],"tags":["input-validation","argument-validation","byte-manipulation","operation-error"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}