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}`,
targetView on GitHub (pinned to 01211a698b)
Solutions
- Edit the file so every `decorate` call has exactly two arguments: the class identifier and a decorators object literal.
- If the call is a wrapper or dynamically-built (e.g. `decorate.apply`), rewrite it manually to `makeObservable` and exclude it from the codemod.
- 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
- Ensure every decorate call passes exactly a class/object and a decorators object literal
- Remove wrapper functions around decorate before codemodding
- Grep for `decorate(` and inspect argument counts before running the codemod
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
- Expected exactly one class declaration for '${target.name}'
- Unexpected type
- Failed to find mobx import, can't add makeObservable as depe
- Found multiple decorators, skipping..
- Found non-mobx decorator @${expr.name}
AI-assisted analysis of mobxjs/mobx@01211a698b (2026-08-28).
Data as JSON: /api/errors/779fa1576f62faaf.
Report an issue: GitHub.