trpc/trpc · error · Error
Could not find a validator fn
Error message
Could not find a validator fn
What it means
`getParseFn` walks the supported parser shapes (Zod-like `.parse/.parseAsync`, Yup `.validateSync`, Superstruct `.create`, Scale `.assert`, custom function, Valibot, ArkType, Standard Schema `~standard`). If none of those signatures is detected on the object passed to `.input()`/`.output()`, it throws 'Could not find a validator fn' - tRPC cannot guess how to run your validator.
Source
Thrown at packages/server/src/unstable-core-do-not-import/parser.ts:139
// ParserScaleEsque
return (value) => {
parser.assert(value);
return value as TType;
};
}
if (isStandardSchema) {
// StandardSchemaEsque
return async (value) => {
const result = await parser['~standard'].validate(value);
if (result.issues) {
throw new StandardSchemaV1Error(result.issues);
}
return result.value;
};
}
throw new Error('Could not find a validator fn');
}
View on GitHub (pinned to acff82332d)
Solutions
- Confirm the validator object exposes one of the supported APIs (e.g. `parser.parse` / `parser['~standard']` / is a function).
- If using an unsupported library, wrap it as a plain function `(input) => result` and pass that function to `.input()`/`.output()`.
- Check that you're passing the schema, not the result of calling it (e.g. `z.object(...)` not `z.object(...).parse(...)`).
- Verify the validator library version matches what tRPC's detection logic expects.
Example fix
// before - JSON schema object is not a parser
.input({ type: 'object', properties: { id: { type: 'number' } } })
// after - wrap an unsupported validator in a function
.input((raw) => {
const v = assertUserShape(raw);
return v;
}) Defensive patterns
Strategy: type-guard
Validate before calling
// Verify the validator exposes a supported API before passing it
function isParser(v: unknown): boolean {
return typeof v === 'function'
|| (v && typeof (v as any).parse === 'function')
|| (v && typeof (v as any).parseAsync === 'function')
|| (v && typeof (v as any).validateSync === 'function')
|| (v && typeof (v as any).create === 'function')
|| (v && typeof (v as any).assert === 'function')
|| (v && '~standard' in (v as any));
} Type guard
import type { Parser } from '@trpc/server';
function asParser<T>(p: Parser): Parser { return p; } Try / catch
try { t.procedure.input(maybeParser); }
catch (e) {
if (/Could not find a validator fn/.test(e.message))
throw new Error('Wrap your validator as a function: (v) => lib.validate(v)');
throw e;
} Prevention
- Use a supported library (zod, valibot, yup, superstruct, arktype, standard-schema).
- Pass the schema object, not the result of calling .parse().
- For unsupported libs, wrap them in a plain function.
- Check the validator version matches tRPC's detection logic.
When it happens
Trigger: Passing a schema class instance whose API doesn't match any supported shape (e.g. a raw JSON Schema object, a Joi schema, or a hand-written class); passing a string/number/null by mistake; a tree-shaking/bundling bug that strips the `parse`/`validate` methods off the prototype; passing an already-unwrapped function that lacks the expected signature.
Common situations: Using a validator library tRPC doesn't auto-detect; double-wrapping (`z.object(...).parse` instead of `z.object(...)`); version skew where the validator lib changed its API; passing `schema.refine(...)` result that returns a different shape.
Related errors
- INTERNAL_SERVER_ERROR
- `id` must not be an empty string as empty string is the same
- BAD_REQUEST
- PARSE_ERROR
- METHOD_NOT_SUPPORTED
AI-assisted analysis of trpc/trpc@acff82332d (2026-08-12).
Data as JSON: /api/errors/659bcbb8bd8aaef8.
Report an issue: GitHub.