mobxjs/mobx · error

Please use `@observable accessor ${String(context.name)}` in

Error message

Please use `@observable accessor ${String(context.name)}` instead of `@observable ${String(context.name)}`

What it means

In MobX 6.13+ with standard (non-legacy) decorators, @observable on a class field (decorator context kind === 'field') is no longer supported because native fields cannot be redefined; decorateObservable20223_ throws via die() directing you to the 'accessor' keyword. This applies to the 2022-3 (Stage 3) decorator transform only.

Source

Thrown at packages/mobx/src/types/observableannotation.ts:54

    proxyTrap: boolean
): boolean | null {
    assertObservableDescriptor(adm, this, key, descriptor)
    return adm.defineObservableProperty_(
        key,
        descriptor.value,
        this.options_?.enhancer_ ?? deepEnhancer,
        proxyTrap
    )
}

export function decorateObservable20223_(
    annotation: Annotation,
    desc,
    context: ClassAccessorDecoratorContext | ClassFieldDecoratorContext
) {
    if (__DEV__) {
        if (context.kind === "field") {
            throw die(
                `Please use \`@observable accessor ${String(
                    context.name
                )}\` instead of \`@observable ${String(context.name)}\``
            )
        }
        assert20223DecoratorType(context, ["accessor"])
    }

    const ann = annotation
    const { kind, name } = context

    if (kind !== "accessor") {
        return
    }

    // Defer ObservableValue construction until first access. The factory is
    // materialised by ObservableObjectAdministration on demand, so unused
    // fields on wide classes never pay the per-instance allocation cost.

View on GitHub (pinned to 01211a698b)

Solutions

  1. Change the field to `@observable accessor someField = value` (requires @babel/plugin-proposal-decorators or TS supporting accessor).
  2. Enable legacy decorators in tsconfig: { "experimentalDecorators": true, "useDefineForClassFields": false }.
  3. Switch to makeObservable/makeAutoObservable without decorators.
  4. Pin MobX < 6.13 temporarily if a full migration isn't possible (short-term only).

Example fix

// before (Stage-3 decorators)
class Store {
  @observable count = 0
}

// after
class Store {
  @observable accessor count = 0
}
Defensive patterns

Strategy: validation

Validate before calling

// tsconfig.json check before using @observable on fields with modern decorators:
// { "compilerOptions": { "experimentalDecorators": true, "useDefineForClassFields": false } }
// or, with Stage-3 decorators, require the accessor keyword:
function assertAccessorDecorator(context) {
  if (context.kind === 'field') {
    throw new Error(`@observable requires 'accessor': use @observable accessor ${String(context.name)}`)
  }
  return context
}

Type guard

function isAccessorContext(ctx) {
  return ctx.kind === 'accessor'
}

Try / catch

try {
  defineStoreClass()
} catch (e) {
  if (String(e.message).includes('@observable accessor')) {
    throw new Error('Migrate @observable fields to @observable accessor (Stage-3 decorators), or enable experimentalDecorators')
  }
  throw e
}

Prevention

When it happens

Trigger: Using native/Stage-3 decorators (TypeScript ~5 with 'experimentalDecorators' omitted/false, or Babel's 2023-11 decorator plugin) and declaring `@observable someField = value` on a class — MobX throws immediately at class definition time.

Common situations: Upgrading MobX to 6.13+ in a project using modern decorators without the legacy flag; new TypeScript 5 projects forgetting experimentalDecorators; copying legacy MobX decorator examples into a Stage-3 decorator codebase.

Related errors


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