{"record":{"id":"1a785701de299ff3","repo":"mastra-ai/mastra","slug":"factory-skill-cancelinflight-must-be-a-boolean","errorCode":null,"errorMessage":"Factory skill cancelInFlight must be a boolean.","messagePattern":"Factory skill cancelInFlight must be a boolean\\.","errorType":"validation","errorClass":"FactoryRuleValidationError","httpStatus":null,"severity":"error","filePath":"mastracode/factory/src/rules/validation.ts","lineNumber":297,"sourceCode":"      assertExactKeys(\n        value,\n        ['type', 'idempotencyKey', 'role', 'skillName', 'prompt', 'arguments', 'precedingMessage', 'cancelInFlight'],\n        'Factory invoke skill decision',\n      );\n      // A run activates a skill or carries a prompt, never both: they are two\n      // ways to author the same kickoff message, so accepting both would leave\n      // the dispatcher picking a winner.\n      if ((value.skillName === undefined) === (value.prompt === undefined)) {\n        throw new FactoryRuleValidationError('Factory skill invocation needs exactly one of skillName or prompt.');\n      }\n      const args = optionalBoundedString(value.arguments, 'Factory skill arguments', MAX_ARGUMENTS_LENGTH);\n      const precedingMessage = optionalBoundedString(\n        value.precedingMessage,\n        'Factory skill preceding message',\n        MAX_MESSAGE_LENGTH,\n      );\n      if (value.cancelInFlight !== undefined && typeof value.cancelInFlight !== 'boolean') {\n        throw new FactoryRuleValidationError('Factory skill cancelInFlight must be a boolean.');\n      }\n      return {\n        type,\n        ...commonCommitFields(value),\n        role: boundedString(value.role, 'Factory skill role', MAX_ROLE_LENGTH, IDENTIFIER_RE),\n        ...(value.skillName === undefined\n          ? { prompt: boundedString(value.prompt, 'Factory skill prompt', MAX_MESSAGE_LENGTH) }\n          : { skillName: boundedString(value.skillName, 'Factory skill name', MAX_SKILL_NAME_LENGTH, SKILL_NAME_RE) }),\n        ...(args ? { arguments: args } : {}),\n        ...(precedingMessage ? { precedingMessage } : {}),\n        ...(value.cancelInFlight === true ? { cancelInFlight: true } : {}),\n      };\n    }\n    case 'sendMessage': {\n      assertExactKeys(\n        value,\n        ['type', 'idempotencyKey', 'role', 'message', 'priority', 'idleBehavior', 'prepareBinding'],\n        'Factory send message decision',","sourceCodeStart":279,"sourceCodeEnd":315,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory/src/rules/validation.ts#L279-L315","documentation":"The optional cancelInFlight field on an invoke-skill decision controls whether an in-flight run of the same key is cancelled; it must be a real boolean when provided. Passing a truthy/falsy non-boolean (strings 'true'/'false', 0/1, null) is rejected so downstream logic can rely on strict boolean semantics.","triggerScenarios":"Emitting an invoke-skill decision where value.cancelInFlight is defined but not typeof 'boolean' — e.g. cancelInFlight: 'true' from parsed JSON/YAML config, cancelInFlight: 1, or cancelInFlight: null.","commonSituations":"Rules whose options come from YAML/JSON config or environment variables where booleans deserialize as strings; template interpolation producing numbers; API responses carrying 0/1 flags.","solutions":["Coerce config values to real booleans with === 'true' or Boolean(...) before assigning, but avoid passing null (use undefined to omit).","Use undefined (field absent) rather than null when no cancel behavior is intended.","Normalize YAML parsing with a schema (e.g. zod boolean) at config-load time."],"exampleFix":"// before\ncancelInFlight: config.cancelInFlight // 'true' (string from env/YAML)\n// after\ncancelInFlight: config.cancelInFlight === undefined ? undefined : config.cancelInFlight === true || config.cancelInFlight === 'true'","handlingStrategy":"type-guard","validationCode":"function checkCancelInFlight(d) {\n  if (d.cancelInFlight !== undefined && typeof d.cancelInFlight !== 'boolean') {\n    throw new Error('cancelInFlight must be boolean or omitted');\n  }\n}","typeGuard":"function hasValidCancelFlag(d: { cancelInFlight?: unknown }): d is { cancelInFlight?: boolean } {\n  const { cancelInFlight } = d;\n  return cancelInFlight === undefined || typeof cancelInFlight === 'boolean';\n}","tryCatchPattern":"try {\n  commitDecision(decision);\n} catch (e) {\n  if (e instanceof FactoryRuleValidationError && /cancelInFlight must be a boolean/.test(e.message)) {\n    const { cancelInFlight, ...rest } = decision;\n    return commitDecision({ ...rest, cancelInFlight: cancelInFlight === true });\n  }\n  throw e;\n}","preventionTips":["Parse YAML/env config with a schema enforcing boolean before use.","Never assign null or 0/1 to boolean flags; use undefined to omit.","Coerce string booleans at the config boundary, not at decision-build time."],"tags":["validation","type-mismatch","factory-rules"],"backgroundTag":"expected-boolean-got-string","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}