mastra-ai/mastra · error · FactoryRuleValidationError

Factory linked work item URL is invalid.

Error message

Factory linked work item URL is invalid.

What it means

validateFactoryRuleDecision validates a 'link' (linked work item) decision before it is committed. When the decision carries a url that is not null, it must be a string, at most MAX_URL_LENGTH characters, and start with http:// or https://. Anything else (wrong type, too long, or a non-http scheme like ftp:// or a bare hostname) throws this error so malformed URLs never reach the factory dispatcher.

Source

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

      }
      return {
        type,
        ...commonCommitFields(value),
        board: enumValue(value.board, FACTORY_RULE_BOARDS, 'Factory transition board'),
        stage: enumValue(value.stage, FACTORY_RULE_STAGES, 'Factory transition stage'),
        ...(message ? { message } : {}),
        ...(value.reenter === true ? { reenter: true } : {}),
      };
    }
    case 'upsertLinkedWorkItem': {
      assertExactKeys(
        value,
        ['type', 'idempotencyKey', 'board', 'source', 'sourceKey', 'title', 'url', 'stage', 'metadata'],
        'Factory linked work item decision',
      );
      const url = value.url;
      if (url !== null && (typeof url !== 'string' || url.length > MAX_URL_LENGTH || !/^https?:\/\//.test(url))) {
        throw new FactoryRuleValidationError('Factory linked work item URL is invalid.');
      }
      const metadata = sanitizeMetadata(value.metadata);
      return {
        type,
        ...commonCommitFields(value),
        board: enumValue(value.board, FACTORY_RULE_BOARDS, 'Factory linked work item board'),
        source: enumValue(value.source, WORK_ITEM_SOURCES, 'Factory linked work item source'),
        sourceKey: boundedString(value.sourceKey, 'Factory linked work item sourceKey', MAX_SOURCE_KEY_LENGTH),
        title: boundedString(value.title, 'Factory linked work item title', MAX_TITLE_LENGTH),
        url,
        stage: enumValue(value.stage, FACTORY_RULE_STAGES, 'Factory linked work item stage'),
        ...(metadata ? { metadata } : {}),
      };
    }
    case 'invokeSkill': {
      assertExactKeys(
        value,
        ['type', 'idempotencyKey', 'role', 'skillName', 'prompt', 'arguments', 'precedingMessage', 'cancelInFlight'],

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Ensure the url is a full absolute http(s) URL, e.g. prefix relative paths with the tracker's origin.
  2. Truncate or regenerate URLs that exceed MAX_URL_LENGTH (strip volatile query/auth parameters).
  3. Set url explicitly to null if no link is intended, instead of an empty or placeholder string.
  4. Validate the URL with the same regex/length checks in your rule code before emitting the decision.

Example fix

// before
url: issue.webUrl ?? '' // '' or relative path fails the http(s) check
// after
url: issue.webUrl?.startsWith('http') ? issue.webUrl : `https://tracker.example.com${issue.webUrl ?? ''}` || null
Defensive patterns

Strategy: validation

Validate before calling

function isValidDecisionUrl(url) {
  const MAX_URL_LENGTH = 2048; // match library cap
  return url === null || (typeof url === 'string' && url.length <= MAX_URL_LENGTH && /^https?:\/\//.test(url));
}
if (!isValidDecisionUrl(decision.url)) throw new Error('Invalid linked work item URL');

Type guard

function isHttpUrl(u: unknown): u is string {
  return typeof u === 'string' && u.length <= 2048 && /^https?:\/\//.test(u);
}

Try / catch

try {
  commitDecision(decision);
} catch (e) {
  if (e instanceof FactoryRuleValidationError && /URL is invalid/.test(e.message)) {
    logger.warn('Dropping decision with invalid URL', { url: decision.url });
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: Committing a factory rule decision of type linking a work item where value.url is a non-string (e.g. a number or object), exceeds MAX_URL_LENGTH, or does not match /^https?:\/\// (e.g. 'www.example.com/item', 'ftp://host/x', or 'javascript:...' URIs).

Common situations: Rule templates interpolating a board item URL from an external tracker that returns relative paths or custom schemes; hand-written rules pasting a short hostname without the scheme; overly long signed URLs from enterprise trackers (e.g. Azure DevOps/Jira with long tokens in query strings) exceeding the length cap.

Related errors


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