nexu-io/open-design · error · Error

resume must be a boolean

Error message

resume must be a boolean

What it means

Thrown by the MCP run-start helper in apps/daemon/src/mcp.ts while assembling the body for POST /api/runs. When the caller supplies a `resume` field it must already be a JS boolean; the MCP layer refuses to coerce strings/numbers because `resume:true` has billing and idempotency side effects (resuming a paused Cloud run via requestId). The guard runs before the request is sent, so no daemon round trip occurs.

Source

Thrown at apps/daemon/src/mcp.ts:2519

        options.analyticsHeaders?.[ANALYTICS_HEADER_HOST_PRODUCT] ?? 'unknown',
      externalPluginId: options.pluginAttribution.context.id,
      externalPluginVersion:
        options.pluginAttribution.context.version,
      distributionMechanism:
        options.pluginAttribution.context.distributionMechanism,
      publisherClass: options.pluginAttribution.context.publisherClass,
      // This payload is client-supplied. The daemon validates it against the
      // request identity/digest and upgrades to session_correlated only after
      // the Run/workflow binding is accepted.
      attributionQuality: 'self_reported',
      pluginWorkflowId: options.pluginAttribution.pluginWorkflowId,
      logicalRequestDigest: logical.digest,
      logicalRequestDigestVersion: logical.version,
      briefState: options.briefState ?? 'not_applicable',
    };
  }
  if (args.resume !== undefined) {
    if (typeof args.resume !== 'boolean') throw new Error('resume must be a boolean');
    body.resume = args.resume;
  }
  if (typeof args.prompt === 'string' && args.prompt.length > 0) {
    body.message = args.prompt;
    body.currentPrompt = args.prompt;
  }
  if (typeof args.skill === 'string' && args.skill.length > 0) body.skillId = args.skill;
  if (Array.isArray(args.skills) && args.skills.length > 0) body.skillIds = args.skills;
  if (typeof args.plugin === 'string' && args.plugin.length > 0) body.pluginId = args.plugin;
  if (typeof args.agent === 'string' && args.agent.length > 0) body.agentId = args.agent;
  if (typeof args.model === 'string' && args.model.length > 0) body.model = args.model;
  if (typeof args.serviceTier === 'string' && args.serviceTier.length > 0) {
    body.serviceTier = args.serviceTier;
  }
  if (args.inputs !== undefined) {
    if (args.inputs === null || typeof args.inputs !== 'object' || Array.isArray(args.inputs)) {
      throw new Error('inputs must be an object');
    }

View on GitHub (pinned to 5be4028344)

Solutions

  1. Pass `resume` as a literal boolean: `resume: true` (or `false`), never quoted.
  2. If the value comes from untyped JSON, coerce before the call: `resume: Boolean(value)` only when you actually intend to resume.
  3. Omit `resume` entirely when you are not resuming a paused Cloud run — the field is optional.
  4. Re-check that requestId is the exact original logical-run id when resuming; resume without it starts a fresh run.

Example fix

// before
{ requestId: id, resume: "true" }
// after
{ requestId: id, resume: true }
Defensive patterns

Strategy: type-guard

Validate before calling

const resume = args.resume;
if (resume !== undefined && typeof resume !== 'boolean') {
  throw new TypeError('resume must be boolean, got ' + typeof resume);
}

Type guard

function isResume(v: unknown): v is boolean | undefined {
  return v === undefined || typeof v === 'boolean';
}

Prevention

When it happens

Trigger: Calling the start_run MCP tool with `resume: "true"`, `resume: 1`, or `resume: "yes"` instead of the literal boolean `true`. Also happens when a client JSON-parses config into a string field, or when an agent emits resume as an enum string.

Common situations: Agent/LLM tool-call arguments arrive as strings from JSON schemas that declare resume as string; shell-driven MCP clients passing `--resume true`; copying a requestId-based retry payload from docs that quote the boolean.

Related errors


AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12). Data as JSON: /api/errors/e1c5edf21d8d9428. Report an issue: GitHub.