laravel/framework · error · InvalidArgumentException

Non-associative array passed to decrementEach method.

Error message

Non-associative array passed to decrementEach method.

What it means

decrementEach() needs column-name => amount pairs to wrap and reference each column. A list-style array (numeric keys) has no column names, so it throws InvalidArgumentException to refuse the call rather than emit ambiguous SQL.

Solutions

  1. Pass an associative map with numeric amounts: ['stock' => 1, 'reserved' => 1].
  2. Convert a column list to a -1 map: array_fill_keys($columns, 1).
  3. Use individual decrement() calls if custom per-column logic is needed.

Example fix

// before
->decrementEach(['stock', 'reserved'])

// after
->decrementEach(['stock' => 1, 'reserved' => 1])
Defensive patterns

Strategy: validation

Validate before calling

if (array_is_list($columns)) {
    throw new InvalidArgumentException('decrementEach requires column => amount pairs.');
}
$query->decrementEach($columns);

Type guard

function isColumnAmountMap(array $a): bool
{
    foreach (array_keys($a) as $k) {
        if (! is_string($k)) {
            return false;
        }
    }
    return true;
}

Prevention

When it happens

Trigger: ->decrementEach([1, 2, 3]) (numeric keys), or ->decrementEach(['stock', 'reserved']) where keys become numeric indices.

Common situations: Passing a flat list of column names expecting a default of -1; passing the wrong variable; refactoring that loses the associative structure.

Related errors


AI-assisted analysis of laravel/framework@e0f6eb3518 (2026-08-11). Data as JSON: /api/errors/82035ed9e54d3a36. Report an issue: GitHub.

Appendix: source

Thrown at src/Illuminate/Database/Query/Builder.php:4494

        return $this->decrementEach([$column => $amount], $extra);
    }

    /**
     * Decrement the given column's values by the given amounts.
     *
     * @param  array<string, float|int|numeric-string>  $columns
     * @param  array<string, mixed>  $extra
     * @return int<0, max>
     *
     * @throws \InvalidArgumentException
     */
    public function decrementEach(array $columns, array $extra = [])
    {
        foreach ($columns as $column => $amount) {
            if (! is_numeric($amount)) {
                throw new InvalidArgumentException("Non-numeric value passed as decrement amount for column: '$column'.");
            } elseif (! is_string($column)) {
                throw new InvalidArgumentException('Non-associative array passed to decrementEach method.');
            }

            $columns[$column] = $this->raw("{$this->grammar->wrap($column)} - $amount");
        }

        return $this->update(array_merge($columns, $extra));
    }

    /**
     * Delete records from the database.
     *
     * @param  mixed  $id
     * @return int
     */
    public function delete($id = null)
    {
        // If an ID is passed to the method, we will set the where clause to check the
        // ID to let developers to simply and quickly remove a single row from this

View on GitHub (pinned to e0f6eb3518)