DEV Community

Cover image for XState v4 code on v5: no error, just NaN
ProvenPin
ProvenPin

Posted on

XState v4 code on v5: no error, just NaN

XState v5 shipped in December 2023, and its migration guide lists a breaking change that is easy to miss: implementation functions now take a single object argument with context, event and other properties.

Code written in the v4 style still looks fine. Here is what it does on xstate 5.33.2.

Before: v4 style on v5

import { createMachine, createActor, assign } from "xstate";

const machine = createMachine({
  initial: "red",
  context: { cycles: 0 },
  states: {
    red: {
      on: {
        NEXT: {
          target: "green",
          actions: assign({ cycles: (context, event) => context.cycles + 1 }),
        },
      },
    },
    green: {},
  },
});

const actor = createActor(machine);
actor.start();
actor.send({ type: "NEXT" });
console.log(actor.getSnapshot().value);          // "green"
console.log(actor.getSnapshot().context.cycles); // NaN
Enter fullscreen mode Exit fullscreen mode

No exception. The machine moves to the next state, and the counter is quietly wrong. In v5, the first argument is { context, event }, so context.cycles is undefined.

After: the v5 version

actions: assign({ cycles: ({ context }) => context.cycles + 1 })
Enter fullscreen mode Exit fullscreen mode

The tested recipe

The ProvenPin recipe xstate-v5-traffic-light models a traffic light with createMachine, createActor, guards and context updates. It pins xstate 5.33.2, tsx 4.23.15 and @types/node 26.6.5, and passed 2 of 2 tests in CI on Oct 18, 2026 on Node v22.23.3. The receipt and full files are here: https://provenpin.com/recipes/xstate-v5-traffic-light/

Use it from your coding agent

ProvenPin is a free MCP server. No API key, no signup.

claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp
Enter fullscreen mode Exit fullscreen mode

Cursor (~/.cursor/mcp.json):

{ "mcpServers": { "provenpin": { "url": "https://mcp.provenpin.com/mcp" } } }
Enter fullscreen mode Exit fullscreen mode

Then ask your agent for "a tested XState v5 recipe", or call get_recipe("xstate-v5-traffic-light"). Setup for VS Code, Windsurf and Cline is in the docs.

Sources: XState migration guide, recipe receipt.

Top comments (0)