colinhacks/zod · error · Error
Invalid template literal part
Error message
Invalid template literal part: ${part._zod.traits} What it means
Thrown by $ZodTemplateLiteral when a part is a schema object (has _zod) and has a _zod.pattern key, but the extracted `source` is falsy after coercion — i.e. part._zod.pattern is an empty string, null, or 0. The constructor already passed the existence check on line 4313, but the resolved source string is empty, so there is no regex fragment to concatenate. The message dumps the part's full traits set for diagnosis.
Solutions
- Ensure the schema's _zod.pattern resolves to a non-empty regex/string (e.g. new RegExp(".+")).
- If using a custom schema, set inst._zod.pattern = /some-source/; in its constructor.
- Replace the offending part with a known-patterned schema like z.string() or z.literal().
- Debug by logging part._zod.pattern before constructing the template to find which part is empty.
Example fix
// before — custom schema with empty pattern
const Empty = z.custom(/* ... */);
Empty._zod.pattern = "";
const T = z.template`${Empty}`;
// after
Empty._zod.pattern = /.+/;
const T = z.template`${Empty}`; Defensive patterns
Strategy: validation
Validate before calling
function assertNonEmptyPattern(part: unknown) {
const p = (part as any)?._zod?.pattern;
const source = p instanceof RegExp ? p.source : p;
if (!source) throw new Error("Template part has empty pattern source.");
} Type guard
function hasNonEmptyPattern(part: unknown): boolean {
const p = (part as any)?._zod?.pattern;
const source = p instanceof RegExp ? p.source : p;
return typeof source === "string" && source.length > 0;
} Prevention
- For custom schemas, always set _zod.pattern to a non-empty RegExp.
- Avoid wrapping schemas in middleware that clears _zod.pattern.
- Unit-test custom schemas inside z.template`...` before shipping.
When it happens
Trigger: A custom schema that sets inst._zod.pattern = "" explicitly; a schema whose pattern getter returns an empty string under some condition; a wrapper that strips the pattern source; rare edge cases where a patterned schema yields an empty source after the startsWith("^")/endsWith("$") slicing.
Common situations: Custom schema authors assigning an empty pattern by mistake; schemas derived from a base whose pattern was deleted; middleware that clears _zod.pattern; edge cases in third-party schema plugins.
Related errors
- Invalid template literal part, no pattern found
- Invalid template literal part
- Invalid UUID version
- A discriminator value for key
- Can't use "invalid_type_error" or "required_error" in…
AI-assisted analysis of colinhacks/zod@2d90846af9 (2026-08-11).
Data as JSON: /api/errors/a4dcc641815932fe.
Report an issue: GitHub.
Appendix: source
Thrown at packages/zod/src/v4/core/schemas.ts:4320
: 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) => {
if (typeof payload.value !== "string") {
payload.issues.push({
input: payload.value,
inst,
expected: "string",View on GitHub (pinned to 2d90846af9)