Validators and schema
Hey, I'm reading through the getting started docs and have a question about validators - do they accept only zod schemas or do they allow any other validation libraries?
https://tanstack.com/start/latest/docs/framework/react/learn-the-basics#mutations
There's a nice spec Standard Schema, and was wondering if I could use other validation library here.
https://github.com/standard-schema/standard-schema
GitHub
GitHub - standard-schema/standard-schema: A standard interface for ...
A standard interface for TypeScript schema validation libraries - standard-schema/standard-schema
Learn the Basics | TanStack Start React Docs
This guide will help you learn the basics behind how TanStack Start works, regardless of how you set up your project. Dependencies TanStack Start is (currently) powered by , and . TanStack Router: A...
86 Replies
extended-salmon•7mo ago
maybe im missing something but isn't Zod done in the standard schema spec. But the Standard Schema website says tanstack router and tanstack form take the standard schema spec
continuing-cyanOP•7mo ago
Yes, zod is spec compliant, and router is on the list. However, I was under the impression that createServerFn comes from Start, so while it's still in beta, it can have a few rough edges such as (potentially) this one.
This PR adds Standard Schema for search params, but the same doesn't have to be true about createServerFn
https://github.com/TanStack/router/pull/2602
GitHub
feat(react-router): implement standard schema into router core by c...
This PR implements Standard Schema in router core. Currently only valibot implements this but the intention is for all validation libraries to implement it. Which means we don't need to sup...
vicious-gold•7mo ago
StandardSchema is more for library authors.
For validator libraries, it's about exposing the their validation callers using a single unified API with standardized type signatures.
For external libraries, it's about consuming the validators using that standardized API. It's what allows us to easily plug in Zod, Valibot, Arktype, etc. without having to have some crazy diverging types for easy library.
Create server function should be spec compliant.
If not, please feel free to open an issue. That'd definitely be something we'd want resolved before 1.0
continuing-cyanOP•7mo ago
Exactly the case I had in mind - the Tanstack Start could support the Standard Schema for validators of server functions, just like the Router does support it for search params.
I started to read the types to figure it out this way, but I wasn't prepared to se soo many of them, so I bailed out for now. I guess I should finally setup example project and just test it out - seems like an easier way to figure it out than just by looking at the router's monorepo (at least for now).
vicious-gold•7mo ago
Looks like it already does.
The type for
ResolveValidatorInput
, which is an export from router-core
, already has StandardSchema implemented.

continuing-cyanOP•7mo ago
I created two server functions - one with Zod and another one with Arktype. I intentionally called both of them with invalid data to verify that the validation works.
The one with Zod returned 500 and
{"$error": { zod error here }}
. The one with Arktype returned 200 if I used the Arktype in the same fashion. I had to wrap it with custom check in validator to ensure that it behaves the same way as the serverFn with Zod as validator.
Is this expected usage?
Zod for comparison
correct-apricot•7mo ago
wouldnt you just do this?
continuing-cyanOP•7mo ago
To be honest I just took it from the docs, and was more focused on getting it to work than look prettier
correct-apricot•7mo ago
no there might be differences in execution
standard schema validators use a different API internally than you did
continuing-cyanOP•7mo ago
Also in the meantime I figured out that arktype can be configured to throw an error when passing invalid data, as it doesn't do it by default
correct-apricot•7mo ago
ah interesting
continuing-cyanOP•7mo ago
Let my try the code you've sent, and get back in a minute with observations
Okay, now both of these return 500, even without configuring arktype to throw. However, in case of arktype the error when passing the schema directly to the validator becomes non-understandable.
With the manual
instanceof
check and throw:
With directly passing arktype schema to the validator:
These come from the message
field in error object.
correct-apricot•7mo ago
do we maybe need to adapt this PR to start as well? https://github.com/TanStack/router/pull/3155
GitHub
fix(react-router): Pass SearchParamError#cause in validateSearch by...
What
Ensure that SearchParamError#cause contains the original parsing error thrown/returned by the validateSearch implementation configured by the user. Notable example: passing valibot schema dire...
continuing-cyanOP•7mo ago
Might be, I don't know to be honest, but looks like worth trying
correct-apricot•7mo ago
can you please create a github issue with a reproducer?
continuing-cyanOP•7mo ago
Sure!
I'll try to apply similar fix to the one in above-linked PR. If I fail then I'll create an issue
So far I've failed to build all packages on the Windows, but it seems to build fine in WSL
correct-apricot•7mo ago
WSL is preferable really
continuing-cyanOP•7mo ago
Yeah, I figured it out 😆
Seems that the issue stems from Arktype errors not being compatible with
JSON.stringify
(at least in this case). I've tried to replace the basic Error
with a custom one like it was in the PR, but when .stringify
is called, a TypeError is thrown. However, I do not know if this is true for other libraries, but calling toString()
yields the correct message:
But it seems to be not enough, as in the end the unreadable message is still being returned on 500 responsecorrect-apricot•7mo ago
what happens if you use arktype in
validateSearch
?
does this work?continuing-cyanOP•7mo ago
Haven't tried, tbh I haven't used anything from tanstack other than query
correct-apricot•7mo ago
hm? arent you using start?
continuing-cyanOP•7mo ago
Well, only since today 😛
correct-apricot•7mo ago
ah
continuing-cyanOP•7mo ago
(I know, start is based on router)
I'll try it tomorrow/Friday, as It's quite late for me
If I do not provide the cause then I get the 200, but with the expected message
continuing-cyanOP•7mo ago
I was looking at other PRs that introduced Standard Schema support in other libraries. From what it seems, other libraries just structure the issues to their own format:
T3-env
https://github.com/t3-oss/t3-env/pull/299/files#diff-adae0bae3aba11742eacaa074b2d6107ed07f1e9e547ca373419587c1c2543c6R97-R105
React-Hook-Form
https://github.com/react-hook-form/resolvers/pull/738/files#diff-24e62aaa55dccd464160d06783b58829c53f23b2d6e340fae16d24b41521757fR6-R21
This way it's possible to break free from errors that each library can throw differently, as the message and (probably path) are the ones which are most useful in case of validation (at least from my PoV). I personally do not care about the underlying error thrown on failed validation, but more about what does the error says about the data passed to it - I might be not seeing something there, so please correct me if I'm wrong.
Also Standard Schema itself offers some utilities such as getDotPath (more suited towards form-supporting libs) and a SchemaError, that can wrap the issues. Maybe the SchemaError should be used instead of calling the JSON.stringify directly?
https://github.com/standard-schema/standard-schema/blob/main/packages/utils/src/SchemaError/SchemaError.ts
GitHub
standard-schema/packages/utils/src/SchemaError/SchemaError.ts at ma...
A standard interface for TypeScript schema validation libraries - standard-schema/standard-schema
continuing-cyanOP•7mo ago
I would appreciate some comment before I proceed further @Manuel Schiller
correct-apricot•7mo ago
sorry I have not been too deeply involved in the runtime parts here.
@Sean Cassiere do you have insights?
vicious-gold•7mo ago
Fabian (author of Valibot and one of the authors of StandardSchema) did the integration of StandardSchema for Router.
For any changes, we'd probably want to align with what Form is doing. Looking at Form's source, they look to be doing what you mentioned.
I'd certainly be accepting of any PR's strengthening our StandardSchema usage.
continuing-cyanOP•7mo ago
By Form, you mean TanStack's Form or RHF (React-Hook-Form)? Because TSF also has a PR for it, also featuring a custom transform of issues, depending on whether they come from the form or particular fields
GitHub
feat: native support for standard schema libraries by Balastrong · ...
This PR closes #1015
Initial support for Standard Schema using a validatorAdapter-like structure embedded in form-core
TODO:
Make it work without explicitly adding an adapter
Example
Doc
More ...
correct-apricot•7mo ago
yes tanstack form
pinging @Leonardo
continuing-cyanOP•7mo ago
Alright, wanted to make sure
correct-apricot•7mo ago
@Leonardo would love to get your insights about standard schema here
how to handle errors, stringify them etc
see above
inland-turquoise•7mo ago
We implement the standard schema interface (aka we expect validators to have a validate function with the expected signature) but what happens inside the validator is out of our control
With the Form latest refactor we directly exposed the error produced by the validator so users should have full control
correct-apricot•7mo ago
so errors are not standardized?
inland-turquoise•7mo ago
They are, but it's the schema library doing that if I'm not mistaken
conscious-sapphire•7mo ago
Hey 👋 happy to answer any Standard Schema questions. Feel free to ping me.
correct-apricot•7mo ago
so the main question is how to stringify errors in a validator agnostic way
other libs seem to extract validation errors like this into a custom structure. is this what we should do as well on the server and then JSON.stringify?
but arktype's errors were not JSON stringifiable
continuing-cyanOP•7mo ago
The issue might lie with the arktype itself. For example invoking
schema['~standard'].validate(value)
on Zod schema, gives the expected spec-compliant issue array. But for Arktype returns ArkErrors
continuing-cyanOP•7mo ago


continuing-cyanOP•7mo ago
For Valibot issues are a bit more info-packed, but still compliant (have both the message and path props)

continuing-cyanOP•7mo ago
Sorry, didn't notice on Arktype that it contains
issues
. But it is a function instead of an array of issues
I've tried with the newest version of arktype too. I'm going to ask about it in the arktype's communitycorrect-apricot•7mo ago
asking it its discord? please tag me there
continuing-cyanOP•7mo ago
Yes, in discord, but I will probably get to it in the afternoon. I'll tag you there once I post it
Posted and pinged
https://discord.com/channels/957797212103016458/1347584777179365426
adverse-sapphire•7mo ago
This seems to suggest the issues are stringifyable https://standardschema.dev/
continuing-cyanOP•7mo ago
It kinda does, but could this example usage be written after the spec was established? Anyway, for now the Arktype doesn't support
toJSON
on ArkError
, so it cannot be used in such way. A one solution that comes to my mind for time being is to create a custom utility or exception that handles the ArkError
, but this is rather a workaround for underlying issue that will be solved eventually (probably)continuing-cyanOP•7mo ago
It is tracked here
https://github.com/arktypeio/arktype/issues/1352
GitHub
JSON serializable ArkErrors · Issue #1352 · arktypeio/arktype
Would make some Standard Schema integrations easier, see standard-schema/standard-schema#49
adverse-sapphire•7mo ago
The example here shows
stringify
. https://github.com/standard-schema/standard-schema/tree/main?tab=readme-ov-file#how-do-i-accept-standard-schemas-in-my-library . hm, so when using arktype these are not meant to be serialised? The problem from our point of view is if one library does not support this then we cannot assume any of them doGitHub
GitHub - standard-schema/standard-schema: A standard interface for ...
A standard interface for TypeScript schema validation libraries - standard-schema/standard-schema
continuing-cyanOP•7mo ago
I had the same example in mind but on the website
The problem from our point of view is if one library does not support this then we cannot assume any of them doTrue, that's why I was thinking in the meantime that maybe pulling out just the fields that are guaranteed by the spec to be there could be a better approach. This way Tanstack wouldn't have to rely on whether the validation library of choice supports serializable errors or not I do not know what to do with the error itself then, but another question is whether the whole error with stacktrace should really be returned in the response when validation fails As I illustrated here, the issues can have much more props than just message and path https://discord.com/channels/719702312431386674/1346288913521705002/1347482036872417320 This might also clarify why some libraries have chosen structuring these errors on their own https://discord.com/channels/719702312431386674/1346288913521705002/1347165037172883486 (but doesn't necessarily mean that was the motivation, could be just a coincidental decision) At the end of the day, I think this is more a responsibility of authors of validation libraries, but I also agree with the quoted statement
conscious-sapphire•7mo ago
This is probably what TanStack Form should do:
You don't have to use our utils package. You can also write the
getDotPath
on your own.continuing-cyanOP•7mo ago
Form actually does something like that. It uses custom path-to-dot function, but the idea is implemented
If you want something similar in tanstack start, then I'm willing to contribute a PR
correct-apricot•7mo ago
bit out of the loop right now, would that solve the JSON issue?
continuing-cyanOP•7mo ago
Short answer: yes
Long answer:
https://discord.com/channels/719702312431386674/1346288913521705002/1347661398166995004
correct-apricot•7mo ago
then we should do it
just a heads up, we are currently freezing commits to main as we are migrating off vinxi. however, you could create that PR now and resolve any merge conflicts once we are ready
we might even merge earlier, just needs coordination
so would be good to have that PR in any case
continuing-cyanOP•7mo ago
That's nice! I'll create a PR and then resolve the conflicts once the migration is over
I should probably notify David from arktype to deprioritize the mentioned issue/task, as this won't be relevant for tanstack anymore, and I felt that this issue put a bit of haste on him
continuing-cyanOP•7mo ago
GitHub
fix: extract props from validatior issues by jkazimierczak · Pull R...
Changes Summary
Replaces naive JSON serialization of validator issues by extracting known properties first, and then serializing extracted values instead of the error itself.
This makes is possible...
continuing-cyanOP•7mo ago
While I'm at it, is the 500 response code really appropriate in this case? I think I always seen 400 or 422 for validation error of the request, while 500 was that something failed within the server itself. I guess the 500 comes from throwing the Error within
execValidator
correct-apricot•7mo ago
can we easily change this?
continuing-cyanOP•7mo ago
Maybe through rising a custom error instead of just plain error and catching it somewhere? I remember there were some properties on ctx, but would have to look into them to see if response status code is there
I'll look into it and let you know
continuing-cyanOP•7mo ago
Soo, the error bubbles up to the server function handler, and response is constructed here:
https://github.com/TanStack/router/blob/a73bf99f1437bc3f17914f576ae321bee11f7560/packages/react-start-server-functions-handler/src/index.ts#L270
Before that there are functions
isRedirect
and isNotFound
. Validation error could possibly be handled in similar fashionGitHub
router/packages/react-start-server-functions-handler/src/index.ts a...
🤖 Fully typesafe Router for React (and friends) w/ built-in caching, 1st class search-param APIs, client-side cache integration and isomorphic rendering. - TanStack/router
correct-apricot•7mo ago
yeah we also had the request from users to throw errors with custom status codes
not sure really how to handle this in a generic fashion
so let's split this up
let's focus on the things you did already and tackle status codes separately
continuing-cyanOP•7mo ago
I already have a working version though 😛
correct-apricot•7mo ago
great
for status codes?
continuing-cyanOP•7mo ago
Yup
correct-apricot•7mo ago
as I wrote above we probably (?) need a generic solution
so that we dont have special treatment for validator errors
but rather allow custom error status codes
and validator errors leverage that
continuing-cyanOP•7mo ago
Ah, in that sense
I'll put my initial scratchpad version into a separate branch and link it here. It won't be included in the PR and you'll see how I've handled that
But in case of making it more generic I do not have any opinion nor idea how this should be approached
correct-apricot•7mo ago
me neither ,yet 😄
continuing-cyanOP•7mo ago
Hmm, are we speaking of custom errors thrown by users within the serverFn?
correct-apricot•7mo ago
yes
we might have a github issue for that, let me check
no I dont find anything
continuing-cyanOP•7mo ago
Then I can see a few approaches:
- expose a base error class that users can extend - then it could be detected through instanceof check in the server function handler
- provide a set of default exceptions - this is how it's done in Nest.js. This let's user throw one of provided exceptions. But again, this comes down to having a single base error class which is subclassed further
Documentation | NestJS - A progressive Node.js framework
Documentation | NestJS - A progressive Node.js framework
Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Reactive Programming).
correct-apricot•7mo ago
we also would want to install error interceptors, similar to nestjs
continuing-cyanOP•7mo ago
I can't give any advice on that, as I was only end user of frameworks so far
Standing on shoulders of giants:P
But sounds like quite nice feature to be present
correct-apricot•7mo ago
just saying this needs more thought to be put into
continuing-cyanOP•7mo ago
Definitely
continuing-cyanOP•7mo ago
As I said, this is rather a POC than a final form, but leaving it as such for now
https://github.com/jkazimierczak/router/commit/8246735a8a0b7fad31d63a0bde289a0789a95a2b
continuing-cyanOP•7mo ago
And this is how the response looks

correct-apricot•7mo ago
can we do
instanceof ValidatorError
on the client?continuing-cyanOP•7mo ago
Haven't checked that
I assume the response has to have some other structure in order for error to be rethrown on client, right? Currently I wrapped the call of serverFn with try catch, but nothing happens
Probably
$error
It fails on deserializationcontinuing-cyanOP•7mo ago
Btw, nice thing about the custom fields on error is that they're visible in the response (
issues
), but again, I haven't figured why it fails to deserialize
continuing-cyanOP•7mo ago
Namely this line throws:
https://github.com/TanStack/router/blob/a73bf99f1437bc3f17914f576ae321bee11f7560/packages/react-start-client/src/serializer.ts#L127
GitHub
router/packages/react-start-client/src/serializer.ts at a73bf99f143...
🤖 Fully typesafe Router for React (and friends) w/ built-in caching, 1st class search-param APIs, client-side cache integration and isomorphic rendering. - TanStack/router
continuing-cyanOP•7mo ago
Well, the instanceof fails on client, no matter if the custom error is thrown directly, or provided as a
cause
to the regular Error
. I've disabled the code in the serverfn handler for now, and used the try catch as described in docs. The instanceof failsServer Functions | TanStack Start React Docs
What are Server Functions? Server functions allow you to specify logic that can be invoked almost anywhere (even the client), but run only on the server. In fact, they are not so different from an API...
correct-apricot•7mo ago
yeah we would need to recreate the actual error class on the client
@lxsmnsyc wondering whether seroval could help here
continuing-cyanOP•7mo ago
Btw, I like how from a simple question about standard schema support this thread turned into a journey of discussing API and implementations, launching debugger session and figuring things out the hard way 😆
I just wanted to spin up a simple Start project and here we are XD
correct-apricot•7mo ago
continuing-cyanOP•7mo ago
Okay, instanceof fails due to the prototype chain missing. So the deserialization would have to restore the prototype for the newly created Error. This makes
instanceof
work on the client. But the drawback is that I do not see how this should be made more generic, as for now I passed the ValidatorError directly
correct-apricot•7mo ago
if we move over to seroval (https://github.com/lxsmnsyc/seroval) users could register their own "plugins" to serialize their error classes
GitHub
GitHub - lxsmnsyc/seroval: Stringify JS values
Stringify JS values. Contribute to lxsmnsyc/seroval development by creating an account on GitHub.
continuing-cyanOP•7mo ago
Also, if you will go with the route of having custom exception hierarchy, remember to preserve the prototype chain. In one of my projects I've used this as a base exception and it worked fine
Registering "plugins" for de/serialization of custom errors sounds like possible solution. I don't see a way to provide correct error class, but it's necessary for setting the correct prototype
Anyway, ending for today 👋