colinhacks/zod · error · Error

Invalid template literal part, no pattern found: ${[...(part

Error message

Invalid template literal part, no pattern found: ${[...(part as any)._zod.traits].shift()}

What it means

Thrown in the `$ZodTemplateLiteral` constructor when one of the parts is a Zod schema object but has no `_zod.pattern` (a regex describing the strings it matches). Template literals build their combined regex from each part's pattern, so any part lacking a pattern cannot contribute. The message reports the part's first trait (its type name).

Source

Thrown at packages/zod/src/v4/core/schemas.ts:4298

export type $PartsToTemplateLiteral<Parts extends $ZodTemplateLiteralPart[]> = [] extends Parts
  ? ``
  : Parts extends [...infer Rest, infer Last extends $ZodTemplateLiteralPart]
    ? Rest extends $ZodTemplateLiteralPart[]
      ? AppendToTemplateLiteral<$PartsToTemplateLiteral<Rest>, Last>
      : never
    : never;

export const $ZodTemplateLiteral: core.$constructor<$ZodTemplateLiteral> = /*@__PURE__*/ core.$constructor(
  "$ZodTemplateLiteral",
  (inst, def) => {
    $ZodType.init(inst, def);
    const regexParts: string[] = [];
    for (const part of def.parts) {
      if (typeof part === "object" && part !== null) {
        // is Zod schema
        if (!part._zod.pattern) {
          // if (!source)
          throw new Error(`Invalid template literal part, no pattern found: ${[...(part as any)._zod.traits].shift()}`);
        }

        const source = part._zod.pattern instanceof RegExp ? part._zod.pattern.source : part._zod.pattern;

        if (!source) throw new Error(`Invalid template literal part: ${part._zod.traits}`);

        const start = source.startsWith("^") ? 1 : 0;
        const end = source.endsWith("$") ? source.length - 1 : source.length;
        regexParts.push(source.slice(start, end));
      } else if (part === null || util.primitiveTypes.has(typeof part)) {
        regexParts.push(util.escapeRegex(`${part}`));
      } else {
        throw new Error(`Invalid template literal part: ${part}`);
      }
    }
    inst._zod.pattern = new RegExp(`^${regexParts.join("")}$`);

    inst._zod.parse = (payload, _ctx) => {

View on GitHub (pinned to 912f0f51b0)

Solutions

  1. Use only string-matching schemas as dynamic parts: `z.string()`, `z.string().regex(...)`, `z.literal('x')`, `z.enum([...])`, or primitives (strings/numbers).
  2. Replace the offending non-string schema with a `z.literal(...)` of the exact text you want interpolated.
  3. For a numeric part, pass the JS number directly (primitives are accepted) rather than `z.number()`.

Example fix

// before
const T = z.templateLiteral([z.literal('user:'), z.number()]); // z.number() has no pattern

// after
const T = z.templateLiteral([z.literal('user:'), z.string().regex(/^\d+$/)]);
// or with a primitive part:
const T2 = z.templateLiteral(['id-', z.enum(['a','b'])]);
Defensive patterns

Strategy: type-guard

Validate before calling

function hasStringPattern(s) {
  return typeof s === 'object' && s !== null && !!s._zod && !!s._zod.pattern;
}
parts.forEach((p) => {
  if (typeof p === 'object' && p !== null && p._zod && !hasStringPattern(p)) {
    throw new Error('template part has no string pattern');
  }
});

Type guard

function isStringPatternSchema(s): boolean {
  return !!s && typeof s === 'object' && !!s._zod && !!s._zod.pattern;
}

Try / catch

try {
  const T = z.templateLiteral(parts);
} catch (e) {
  if (e instanceof Error && e.message.startsWith('Invalid template literal part, no pattern')) {
    // replace the non-string-pattern schema with z.literal(...) or a primitive
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing a non-string-pattern schema into `z.templateLiteral(...)` — e.g. `z.object({...})`, `z.number()` (numbers have no string pattern), `z.boolean()`, `z.any()`, or a custom schema without a `_zod.pattern`. Only schemas that match strings with a regex (like `z.string().email()`, `z.literal('x')`, `z.enum([...])`) are valid template parts.

Common situations: Composing a template literal from mixed schema types without realizing only string-patterned schemas work; passing a nested object schema expecting it to be stringified.

Related errors


AI-assisted analysis of colinhacks/zod@912f0f51b0 (2026-08-03). Data as JSON: /data/errors/cc413bd95ec4ac03.json. Report an issue: GitHub.