mobxjs/mobx · warning

Expected a decorate call with two arguments

Error message

Expected a decorate call with two arguments

What it means

The mobx-undecorate codemod rewrites legacy `decorate(klass, decorators)` calls into `makeObservable` calls. The decorate call must take exactly two arguments: the class (or object) and the decorators map. If it finds a `decorate(...)` call with any other argument count, it warns and skips that call, leaving it untransformed.

Source

Thrown at packages/mobx-undecorate/src/undecorate.ts:165

            if (decorateIndex !== -1) {
                im.value.specifiers?.splice(decorateIndex, 1)
            }
        }
    })

    // rewrite all decorate calls to class decorators
    if (usesDecorate) {
        source
            .find(j.CallExpression)
            .filter(
                callPath =>
                    j.Identifier.check(callPath.value.callee) &&
                    callPath.value.callee.name === "decorate"
            )
            .forEach(callPath => {
                let canRemoveDecorateCall = true
                if (callPath.value.arguments.length !== 2) {
                    warn("Expected a decorate call with two arguments", callPath.value)
                    return
                }
                const target = callPath.value.arguments[0]
                const decorators = callPath.value.arguments[1]

                if (!j.Identifier.check(target)) {
                    // not targeting a class, just swap it with makeObservable
                    changed = true
                    // @ts-ignore // TODO: or "observable" ?
                    callPath.value.callee.name = "makeObservable"
                    needsInitializeImport = true
                    return
                }
                const declarations = callPath.scope.getBindings()[target.name]
                if (declarations.length === 0) {
                    warn(
                        `Expected exactly one class declaration for '${target.name}' but found ${declarations.length}`,
                        target

View on GitHub (pinned to 01211a698b)

Solutions

  1. Edit the file so every `decorate` call has exactly two arguments: the class identifier and a decorators object literal.
  2. If the call is a wrapper or dynamically-built (e.g. `decorate.apply`), rewrite it manually to `makeObservable` and exclude it from the codemod.
  3. Remove dead/obsolete decorate calls before running the codemod.

Example fix

// before
decorate(Store, { count: observable }, someExtra)
// after
decorate(Store, { count: observable })
Defensive patterns

Strategy: validation

Validate before calling

import fs from 'fs'
const src = fs.readFileSync(file, 'utf8')
const bad = [...src.matchAll(/decorate\s*\(([^;]*?)\)/g)]
  .filter(m => (m[1].match(/,/g) || []).length !== 1)
if (bad.length) throw new Error(`decorate calls without exactly 2 args in ${file}`)

Type guard

function hasTwoArgs(node) {
  return Array.isArray(node.arguments) && node.arguments.length === 2
}

Prevention

When it happens

Trigger: Running the codemod on a file containing `decorate(X, {...}, extraArg)` or `decorate(X)` — i.e. a decorate invocation whose `arguments.length !== 2`.

Common situations: Hand-written helper wrappers around decorate, commented-out or partially edited decorate calls, or code that spread extra arguments into decorate (e.g. debugging leftovers).

Related errors


AI-assisted analysis of mobxjs/mobx@01211a698b (2026-08-28). Data as JSON: /api/errors/779fa1576f62faaf. Report an issue: GitHub.