mastra-ai/mastra · error

CursorSDKAgent resumeData must include a message.

Error message

CursorSDKAgent resumeData must include a message.

What it means

validateCursorResumeData requires resumeData to be a record containing a 'message' property — the conversation payload Cursor uses to resume an agent run. It throws when resumeData is not an object or lacks the message key.

Source

Thrown at agent-sdks/cursor/src/index.ts:290

    });
    return this.#createdAgent;
  }

  private async resolveResumeCursorAgent(resumeData: CursorSDKAgentResumeData): Promise<SDKAgent> {
    if (!resumeData.agentId) {
      return this.resolveCursorAgent();
    }

    return CursorAgent.resume(resumeData.agentId, {
      ...toCursorCreateOptions(this.options),
      ...resumeData.sdkOptions,
    });
  }
}

function validateCursorResumeData(resumeData: CursorSDKAgentResumeData): CursorSDKAgentResumeData {
  if (!toRecord(resumeData) || !('message' in resumeData)) {
    throw new Error('CursorSDKAgent resumeData must include a message.');
  }

  if (resumeData.agentId !== undefined && typeof resumeData.agentId !== 'string') {
    throw new Error('CursorSDKAgent resumeData.agentId must be a string when provided.');
  }

  return resumeData;
}

function assertStructuredOutputUnsupported(options?: unknown): void {
  const structuredOutput = toRecord(toRecord(options)?.structuredOutput);
  if (structuredOutput && 'schema' in structuredOutput) {
    throw new Error(
      'CursorSDKAgent does not support structuredOutput because the Cursor TypeScript SDK does not expose a schema-constrained output API.',
    );
  }
}

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Include the original conversation message in resumeData: resume({ message: savedMessage }).
  2. Persist the full CursorSDKAgentResumeData object returned/required by the agent, not just the agentId.
  3. Check resumeData is a non-null object with a 'message' key before calling resume.

Example fix

// before
await agent.resume({ agentId: saved.agentId });
// after
await agent.resume({ message: saved.message, agentId: saved.agentId });
Defensive patterns

Strategy: validation

Validate before calling

function canResumeCursor(data: unknown): boolean {
  return typeof data === 'object' && data !== null && 'message' in data;
}
if (!canResumeCursor(saved)) throw new Error('Saved Cursor resume data is missing message');
await agent.resume(saved);

Type guard

function isCursorResumeData(v: unknown): v is CursorSDKAgentResumeData {
  return typeof v === 'object' && v !== null && 'message' in v &&
    ((v as any).agentId === undefined || typeof (v as any).agentId === 'string');
}

Try / catch

try {
  await agent.resume(saved);
} catch (e) {
  if (e instanceof Error && e.message.includes('resumeData must include a message')) {
    // start a fresh run instead
    await agent.generate(prompt);
  } else throw e;
}

Prevention

When it happens

Trigger: cursorSDKAgent.resume(data) called with an empty object, a non-object (string/null/undefined), or an object holding only other fields like agentId but no message.

Common situations: Saving only the Cursor agentId after a run and trying to resume with just { agentId }; resuming with resume data persisted from a different SDK (e.g. Claude's sessionId-shaped data).

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/1829ef666c2645f3. Report an issue: GitHub.