mastra-ai/mastra · error · FactoryRuleValidationError

Factory transition reenter must be a boolean.

Error message

Factory transition reenter must be a boolean.

What it means

For a 'transition' decision, the optional reenter field must be a boolean: it controls whether the target stage may be re-entered if already active. If reenter is defined but not true/false, this error is thrown by validateFactoryRuleDecision.

Source

Thrown at mastracode/factory/src/rules/validation.ts:229

  if (typeof type !== 'string') throw new FactoryRuleValidationError('Factory rule decision type is required.');

  switch (type) {
    case 'reject': {
      assertExactKeys(value, ['type', 'code', 'reason'], 'Factory reject decision');
      return {
        type,
        code: enumValue(value.code, REJECTION_CODES, 'Factory rejection code'),
        reason: boundedString(value.reason, 'Factory rejection reason', MAX_REASON_LENGTH),
      };
    }
    case 'transition': {
      assertExactKeys(
        value,
        ['type', 'idempotencyKey', 'board', 'stage', 'message', 'reenter'],
        'Factory transition decision',
      );
      if (value.reenter !== undefined && typeof value.reenter !== 'boolean') {
        throw new FactoryRuleValidationError('Factory transition reenter must be a boolean.');
      }
      let message: { text: string; role?: string } | undefined;
      if (value.message !== undefined) {
        if (!isPlainObject(value.message)) {
          throw new FactoryRuleValidationError('Factory transition message must be an object.');
        }
        assertExactKeys(value.message, ['text', 'role'], 'Factory transition message');
        const role =
          value.message.role === undefined
            ? undefined
            : boundedString(value.message.role, 'Factory transition message role', MAX_ROLE_LENGTH, IDENTIFIER_RE);
        message = {
          text: boundedString(value.message.text, 'Factory transition message text', MAX_MESSAGE_LENGTH),
          ...(role ? { role } : {}),
        };
      }
      return {
        type,

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Coerce to boolean explicitly: reenter: Boolean(flag), or pass true/false literals
  2. Convert string flags with flag === 'true'
  3. Replace null with undefined (omit the key) when reenter is not applicable
  4. Type the decision object as the library's FactoryRuleDecision input type so TypeScript catches it

Example fix

// before
decision({ type: 'transition', ..., reenter: opts.reenter ?? null })
// after
decision({ type: 'transition', ..., reenter: Boolean(opts.reenter) })
Defensive patterns

Strategy: validation

Validate before calling

function assertReenter(d) {
  if (d?.reenter !== undefined && typeof d.reenter !== 'boolean') {
    throw new TypeError('transition decision reenter must be boolean');
  }
}

Type guard

const hasValidReenter = (v): v is { reenter?: boolean } =>
  (v as any)?.reenter === undefined || typeof (v as any).reenter === 'boolean';

Try / catch

try {
  return decision(d);
} catch (e) {
  if (e instanceof FactoryRuleValidationError && e.message === 'Factory transition reenter must be a boolean.') {
    logger.error('Bad reenter value', { reenter: d.reenter });
    return decision({ ...d, reenter: Boolean(d.reenter) });
  }
  throw e;
}

Prevention

When it happens

Trigger: decision({ type: 'transition', ..., reenter: 'yes' }), reenter: 1, reenter: null (null is defined and not boolean), or a truthy/falsy expression not coerced to boolean.

Common situations: Passing user/config string flags ('true'/'false') straight through; using 0/1 from a database column; null from an optional binding where undefined was intended.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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