JuliusBrussee/caveman · error · Error

cave_mastra_max_steps_invalid

cave_mastra_max_steps_invalid

Error message

cave_mastra_max_steps_invalid

What it means

`createMastraAdapter` validates the optional `options.maxSteps`: it must be `undefined` or satisfy `Number.isSafeInteger(maxSteps) && maxSteps > 0`. Zero, negatives, fractions, `NaN`, `Infinity`, and non-numbers (including numeric strings read from env/config) throw `cave_mastra_max_steps_invalid` at adapter construction, before any generation happens. To use Mastra's default, omit the option entirely rather than passing 0.

Solutions

  1. Parse config strictly: `Number.parseInt(raw, 10)` then check `Number.isSafeInteger(v) && v > 0` before passing
  2. Omit `maxSteps` entirely when you want Mastra's default
  3. Validate at config-load time so the failure names the config key, not the adapter factory

Example fix

// before
const maxSteps = Number(cfg.get('MAXSTEPS')); // NaN when unset
createMastraAdapter(identity, agent, { maxSteps });
// after
const raw = cfg.get('MAXSTEPS');
const maxSteps = raw === undefined ? undefined : Number.parseInt(raw, 10);
if (maxSteps !== undefined && (!Number.isSafeInteger(maxSteps) || maxSteps <= 0)) {
  throw new Error(`invalid MAXSTEPS: ${raw}`);
}
createMastraAdapter(identity, agent, maxSteps === undefined ? {} : { maxSteps });
Defensive patterns

Strategy: type-guard

Validate before calling

const raw = cfg.get('MAXSTEPS');
const maxSteps = raw === undefined || raw === '' ? undefined : Number.parseInt(raw, 10);
if (maxSteps !== undefined && !isPositiveSafeInteger(maxSteps)) {
  throw new Error(`invalid MAXSTEPS config: ${JSON.stringify(raw)}`);
}
return createMastraAdapter(identity, agent, maxSteps === undefined ? {} : { maxSteps });

Type guard

function isPositiveSafeInteger(v: unknown): v is number {
  return typeof v === 'number' && Number.isSafeInteger(v) && v > 0;
}

Prevention

When it happens

Trigger: `maxSteps: Number(process.env.MASTRA_MAX_STEPS)` when the variable is unset (NaN); a JSON config supplying `"maxSteps": "25"` as a string; `maxSteps: 0` intended to mean "no limit"; a computed float like `12.5`.

Common situations: Reading limits from env vars or config files without integer coercion; passing 0 to disable; arithmetic producing non-integer values.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@766dce6b13 (2026-08-18). Data as JSON: /api/errors/13ec1893e15c40c0. Report an issue: GitHub.

Appendix: source

Thrown at packages/agent/src/adapters.ts:302

    error?: unknown;
    finishReason?: unknown;
    response?: { modelId?: unknown };
  }>;
}

export interface MastraAdapterOptions {
  /** Mastra's per-generate maximum number of sequential LLM calls. */
  maxSteps?: number;
}

export function createMastraAdapter(
  identity: HarnessAdapterIdentity,
  agent: MastraAgentBinding,
  options: MastraAdapterOptions = {},
): HarnessAdapter {
  const maxSteps = options.maxSteps;
  if (maxSteps !== undefined && (!Number.isSafeInteger(maxSteps) || maxSteps <= 0)) {
    throw new Error("cave_mastra_max_steps_invalid");
  }
  assertSupportedUpstream(identity, MASTRA_VERSION, "mastra", "@mastra/core");
  return createHarnessAdapter("mastra", identity, {
    package: "@mastra/core/agent",
    class: "Agent",
    method: "generate",
    usage: "FullOutput.totalUsage",
    ...(maxSteps === undefined ? {} : { preExecutionControls: { maxSteps } }),
  }, async (request) => {
    const startedAt = performance.now();
    const response = await agent.generate(request.prompt, {
      maxProcessorRetries: 0,
      runId: request.runID,
      ...(maxSteps === undefined ? {} : { maxSteps }),
      ...(request.signal === undefined ? {} : { abortSignal: request.signal }),
    });
    if (response.error !== undefined || terminalFinishReason(response.finishReason) === false) {
      throw new Error("cave_mastra_terminal_failure");

View on GitHub (pinned to 766dce6b13)