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
- Use only string-matching schemas as dynamic parts: `z.string()`, `z.string().regex(...)`, `z.literal('x')`, `z.enum([...])`, or primitives (strings/numbers).
- Replace the offending non-string schema with a `z.literal(...)` of the exact text you want interpolated.
- 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
- Only use string-matching schemas (z.string(), z.literal, z.enum) or primitives in template literals.
- For numeric content, pass the primitive number or a z.string().regex(...) instead of z.number().
- Unit-test template literal construction to catch bad parts early.
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
- Invalid template literal part: ${part._zod.traits}
- Invalid template literal part: ${part}
- Invalid discriminated union option at index "${def.options.i
- Invalid discriminated union option at index "${def.options.i
- Duplicate discriminator value "${String(v)}"
AI-assisted analysis of colinhacks/zod@912f0f51b0 (2026-08-03).
Data as JSON: /data/errors/cc413bd95ec4ac03.json.
Report an issue: GitHub.