oxc-project/oxc · warning · OxcDiagnostic
Do not spread accumulators in loops
Error message
Do not spread accumulators in loops
What it means
Oxlint performance rule `oxc/no_accumulating_spread`, loop variant: an object accumulator declared outside a loop is reassigned with an object spread (`{ ...acc, ... }`) inside the loop body. Each iteration copies all previously accumulated properties, so total work is O(n^2) in the number of iterations. The rule suggests `Object.assign()` mutation instead, and labels the accumulator declaration, the spread, and the loop (primary).
Source
Thrown at crates/oxc_linter/src/rules/oxc/no_accumulating_spread.rs:55
])
}
fn reduce_unknown(spread_span: Span, reduce_span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Do not spread accumulators in Array.prototype.reduce()")
.with_help("Consider using `Object.assign()` or `Array.prototype.push()` to mutate the accumulator instead.")
.with_note("Using spreads within accumulators leads to `O(n^2)` time complexity.")
.with_labels([
spread_span.label("From this spread"),
reduce_span.label("For this reduce")
])
}
fn loop_spread_likely_object_diagnostic(
accumulator_decl_span: Span,
spread_span: Span,
loop_span: Span,
) -> OxcDiagnostic {
OxcDiagnostic::warn("Do not spread accumulators in loops")
.with_help("Consider using `Object.assign()` to mutate the accumulator instead.")
.with_note("Using spreads within accumulators leads to `O(n^2)` time complexity.")
.with_labels([
accumulator_decl_span.label("From this accumulator"),
spread_span.label("From this spread"),
loop_span.primary_label("For this loop"),
])
}
fn loop_spread_likely_array_diagnostic(
accumulator_decl_span: Span,
spread_span: Span,
loop_span: Span,
) -> OxcDiagnostic {
OxcDiagnostic::warn("Do not spread accumulators in loops")
.with_help("Consider using `Array.prototype.push()` to mutate the accumulator instead.")
.with_note("Using spreads within accumulators leads to `O(n^2)` time complexity.")
.with_labels([
accumulator_decl_span.label("From this accumulator"),View on GitHub (pinned to e1e7af627c)
Solutions
- Mutate in place: `Object.assign(acc, { [x.key]: x.value })` or plain `acc[x.key] = x.value` inside the loop
- Use a `Map` during the loop and convert with `Object.fromEntries(map)` once after it
- If immutability per iteration is required (e.g. snapshots), disable the rule locally and document why the quadratic cost is acceptable
Example fix
// before
let acc = {};
for (const x of xs) {
acc = { ...acc, [x.key]: x.value };
}
// after
const acc = {};
for (const x of xs) {
acc[x.key] = x.value;
} Defensive patterns
Strategy: fallback
Prevention
- In loops, mutate accumulators (Object.assign or direct assignment) instead of reassigning spreads
- Use Map/Set for accumulation and convert once after the loop
- Run `oxlint` with the oxc plugin in CI to catch accumulating spreads before merge
When it happens
Trigger: Code shaped like `let acc = {}; for (const x of xs) { acc = { ...acc, [x.key]: x.value }; }` (or while/do-while), where the accumulator is declared before the loop, the analysis concludes it is likely an object, and it is spread inside the loop.
Common situations: Merging per-item results into a single object inside for-of loops; incremental config/props building in React render loops; enabling the `oxc` plugin's performance rules on existing code for the first time.
Related errors
- Unexpected `await` inside a loop.
- Unexpected sync method: '{property_name}'.
- Do not spread accumulators in Array.prototype.reduce()
- Barrel file detected, {total} modules are loaded which excee
- The Context `value` prop should not be constructed.
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/998591c151c0fe33.
Report an issue: GitHub.