mastra-ai/mastra · error · FactoryRuleValidationError

${label} is invalid.

Error message

${label} is invalid.

What it means

After confirming the value is a string, boundedString rejects it if it is empty after trimming, exceeds the field's max length (e.g. idempotencyKey 256, message 8192, role 32, version 128), or fails the optional pattern (IDENTIFIER_RE for roles/keys, SKILL_NAME_RE for skill names). The message includes the field label so the developer knows which field failed.

Source

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

function isPlainObject(value: unknown): value is Record<string, unknown> {
  if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;
  const prototype = Object.getPrototypeOf(value);
  return prototype === Object.prototype || prototype === null;
}

function assertExactKeys(value: Record<string, unknown>, keys: readonly string[], label: string): void {
  const allowed = new Set(keys);
  if (Object.keys(value).some(key => !allowed.has(key))) {
    throw new FactoryRuleValidationError(`${label} contains an unsupported field.`);
  }
}

function boundedString(value: unknown, label: string, max: number, pattern?: RegExp): string {
  if (typeof value !== 'string') throw new FactoryRuleValidationError(`${label} must be a string.`);
  const normalized = value.trim();
  if (normalized.length === 0 || normalized.length > max || (pattern && !pattern.test(normalized))) {
    throw new FactoryRuleValidationError(`${label} is invalid.`);
  }
  return normalized;
}

function optionalBoundedString(value: unknown, label: string, max: number): string | undefined {
  if (value === undefined) return undefined;
  return boundedString(value, label, max);
}

function enumValue<T extends string>(value: unknown, allowed: readonly T[], label: string): T {
  if (typeof value !== 'string' || !allowed.includes(value as T)) {
    throw new FactoryRuleValidationError(`${label} is invalid.`);
  }
  return value as T;
}

export function normalizeFactoryRuleJsonValue(
  value: unknown,

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Trim the value yourself and check it is non-empty before passing it.
  2. For role/key fields, use /^[a-z0-9][a-z0-9_-]*$/i-compatible identifiers (letters, digits, underscore, hyphen only).
  3. For skillName, use lowercase kebab-case, e.g. 'run-tests'.
  4. Truncate long text to the documented max (message 8192, title 512, reason 512, arguments 4096) before building the decision.

Example fix

// before
role: 'Backend Dev'
// after
role: 'backend-dev'
Defensive patterns

Strategy: validation

Validate before calling

const check = (s: string, max: number, re?: RegExp) => {
  const t = s.trim();
  if (!t || t.length > max || (re && !re.test(t))) throw new RangeError(`invalid ${s.slice(0, 20)}`);
};
check(role, 32, /^[a-z0-9][a-z0-9_-]*$/i);

Type guard

const isValidIdentifier = (v: unknown): v is string => typeof v === 'string' && /^[a-z0-9][a-z0-9_-]*$/i.test(v.trim());

Try / catch

try {
  validateFactoryRuleDecision(decision);
} catch (e) {
  if (e instanceof FactoryRuleValidationError && e.message.endsWith('is invalid.')) {
    throw new Error(`Constraint violation, fix value/format: ${e.message}`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing an empty or whitespace-only string; a role like 'My Role!' failing IDENTIFIER_RE; a skillName like 'My Skill' failing SKILL_NAME_RE (must be kebab-case lowercase); an oversized message (>8192 chars) or title (>512) or idempotencyKey (>256); a metadata key with characters outside [a-z0-9_-] or longer than 128.

Common situations: Whitespace-padded values from user input or clipboard paste, skill names with spaces or uppercase from hand-written config, very long error text stuffed into the message field, auto-generated ids with colons or slashes (UUID with dashes is fine, but ':' is not).

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/adf8a57b153c37a9. Report an issue: GitHub.