colinhacks/zod · error · Error

Invalid template literal part: ${part}

Error message

Invalid template literal part: ${part}

What it means

Thrown in `$ZodTemplateLiteral` when a part is neither a Zod schema object (no `_zod`), nor `null`, nor a primitive (string/number/boolean/undefined per `util.primitiveTypes`). Template literal parts must be primitives (interpolated literally) or string-patterned Zod schemas; anything else is rejected.

Source

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

    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) => {
      if (typeof payload.value !== "string") {
        payload.issues.push({
          input: payload.value,
          inst,
          expected: "string",
          code: "invalid_type",
        });
        return payload;
      }

      inst._zod.pattern.lastIndex = 0;

      if (!inst._zod.pattern.test(payload.value)) {

View on GitHub (pinned to 912f0f51b0)

Solutions

  1. Only pass primitives (string/number/boolean) or Zod schemas as template parts.
  2. If you need a dynamic object's value, extract a primitive field (e.g. `obj.id`) or stringify it into a `z.literal(String(obj))`.
  3. Filter/map the parts array before passing it to ensure every element is a primitive or schema.

Example fix

// before
const T = z.templateLiteral([z.literal('u:'), { id: 5 }]);

// after
const T = z.templateLiteral([z.literal('u:'), z.literal('5')]);
// or build the literal from a primitive string:
const T2 = z.templateLiteral(['u:', String(5)]);
Defensive patterns

Strategy: type-guard

Validate before calling

const PRIMS = new Set(['string','number','boolean','bigint','symbol','undefined']);
function isValidTemplatePart(p) {
  if (p === null) return true;
  if (PRIMS.has(typeof p)) return true;
  if (typeof p === 'object' && p !== null && p._zod) return true;
  return false;
}
parts.forEach((p) => { if (!isValidTemplatePart(p)) throw new Error('invalid template part'); });

Type guard

const PRIMS = new Set(['string','number','boolean','bigint','symbol','undefined']);
function isValidTemplatePart(p): boolean {
  if (p === null) return true;
  if (PRIMS.has(typeof p)) return true;
  return typeof p === 'object' && p !== null && !!p._zod;
}

Try / catch

try {
  const T = z.templateLiteral(parts);
} catch (e) {
  if (e instanceof Error && e.message.startsWith('Invalid template literal part:')) {
    // filter parts to primitives/schemas before rebuilding
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing a plain JS object, an array, a `Date`, a `Symbol`, or any non-schema non-primitive as a part to `z.templateLiteral([...])`. E.g. `z.templateLiteral([{ foo: 1 }])`.

Common situations: Passing config objects or class instances expecting them to be stringified; spreading an array of mixed parts that includes objects.

Related errors


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