{"id":"92318cf58349f7f5","repo":"laravel/framework","slug":"non-numeric-value-passed-to-decrement-method","errorCode":null,"errorMessage":"Non-numeric value passed to decrement method.","messagePattern":"Non-numeric value passed to decrement method\\.","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"src/Illuminate/Database/Query/Builder.php","lineNumber":4473,"sourceCode":"            $columns[$column] = $this->raw(\"{$this->grammar->wrap($column)} + $amount\");\n        }\n\n        return $this->update(array_merge($columns, $extra));\n    }\n\n    /**\n     * Decrement a column's value by a given amount.\n     *\n     * @param  string  $column\n     * @param  float|int  $amount\n     * @return int<0, max>\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function decrement($column, $amount = 1, array $extra = [])\n    {\n        if (! is_numeric($amount)) {\n            throw new InvalidArgumentException('Non-numeric value passed to decrement method.');\n        }\n\n        return $this->decrementEach([$column => $amount], $extra);\n    }\n\n    /**\n     * Decrement the given column's values by the given amounts.\n     *\n     * @param  array<string, float|int|numeric-string>  $columns\n     * @param  array<string, mixed>  $extra\n     * @return int<0, max>\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function decrementEach(array $columns, array $extra = [])\n    {\n        foreach ($columns as $column => $amount) {\n            if (! is_numeric($amount)) {","sourceCodeStart":4455,"sourceCodeEnd":4491,"githubUrl":"https://github.com/laravel/framework/blob/bd6b5437e6ad87bb49f9b426724f07a9f64e9683/src/Illuminate/Database/Query/Builder.php#L4455-L4491","documentation":"Thrown by decrement when $amount fails is_numeric(). decrement mirrors increment: it generates `SET col = col - amount` and requires the amount to be numeric. Default is 1, so the error only appears when a caller explicitly passes a non-numeric value (null, string text, array, object).","triggerScenarios":"`->decrement('stock', $request->qty)` when qty is null or a non-numeric string. Passing a value read from a nullable column back as the decrement amount. Negative strings like '-3' are numeric and accepted.","commonSituations":"Cart/inventory decrement endpoints receiving unvalidated JSON; counters fed by user input; converting a manual `update(['stock' => DB::raw('stock - '.$n)])` where $n is tainted.","solutions":["Validate input: `$request->validate(['qty' => 'required|numeric|min:0']);`.","Cast with a default: `->decrement('stock', (float) $request->input('qty', 1))`.","Reject empty/null before calling.","Use request form requests to enforce numeric on the decrement amount."],"exampleFix":"// before\n$product->decrement('stock', $request->input('qty'));\n// when qty is null => Non-numeric value passed to decrement method.\n\n// after\n$request->validate(['qty' => 'required|numeric|min:0']);\n$product->decrement('stock', (float) $request->qty);","handlingStrategy":"validation","validationCode":"if (! is_numeric($amount)) {\n    throw new \\InvalidArgumentException('decrement amount must be numeric, got: '.get_debug_type($amount));\n}\n$model->decrement($column, (float) $amount);","typeGuard":"function isNumericAmount(mixed $amount): bool\n{\n    return is_int($amount) || is_float($amount) || (is_string($amount) && is_numeric($amount));\n}","tryCatchPattern":"// Validate the amount before calling; catching is rarely useful for a programming/type error.","preventionTips":["Validate request inputs with 'numeric' rules before decrementing.","Cast with a sane default.","Reject empty/null form fields with form requests."],"tags":["query-builder","decrement","numeric","invalid-argument"],"analyzedSha":"bd6b5437e6ad87bb49f9b426724f07a9f64e9683","analyzedAt":"2026-08-06T00:28:32.783Z","schemaVersion":2}