RJ
RJ14mo ago

Math.random unsupported while evaluating schema

I'm working on my Effect wrapper library for Convex, and discovered through this work that importing a module which uses Math.random produces the following error when running convex dev:
400 Bad Request: Error: Hit an error while evaluating your schema:
Uncaught Error: Math.random unsupported when evaluating schema
400 Bad Request: Error: Hit an error while evaluating your schema:
Uncaught Error: Math.random unsupported when evaluating schema
1. Is there any way for me to work around this right now? 2. Would it be possible to treat Math.random in this context in the same way that it is treated in Convex functions?
41 Replies
mikeysee
mikeysee14mo ago
What do you need Math.random for when creating a schema if you dont mind me asking?
RJ
RJOP14mo ago
I don't, but it's being invoked by a dependency (although I am certain that its results are not used in the context in which I'm using said dependency)
mikeysee
mikeysee14mo ago
Ah, its one of those top level module import usages of Math.random? fun! Im sorry I dont have any answer for to help you with this one RJ other than dont use that Dependency. Hopefully a Convex team member will be able to offer more suggestions
ballingt
ballingt14mo ago
We chose not to implement this in the schema environment because it seemed like you shouldn't use it there — and we wanted it to fail in an obvious way instead of always returning 0 because silently failing could be a security issue. Re (1) is there any way to work around it: I'm not sure, any approach like patching Math.random to have different behavior seems like a bad idea because you might do that patch when schema.js is imported by other files, causing Math.random() not to work. Re (2) would it be possible to treat Math.random the way it is in other contexts: yes it's possible, and the implications don't sound that much worse that using Math.random() for a global variable that other behavior is based on when e.g. defining mutations or queries. @RJ would love to hear how it's coming up, treating it other ways isn't out of the question; if it's blocking work on your library that's important
RJ
RJOP14mo ago
You evidently didn't anticipate such profane use cases as mine 🦹‍♂️ This would work beautifully for my needs here, I think Here's where it's coming up: - As the seed to a random number generator class: https://github.com/Effect-TS/effect/blob/e0ef64102b05c874e844f680f53746821609e1b6/src/Utils.ts#L541 - Which is instantiated for use in the Hash module: https://github.com/Effect-TS/effect/blob/e0ef64102b05c874e844f680f53746821609e1b6/src/Hash.ts#L16 - Which is used for efficient comparison of data (like Rust's Hash trait, I believe, or Haskell's Hashable) So treating Math.random() as its treated in Convex functions should therefore work fine here, in the sense that it shouldn't cause any issues with how the Hash trait (which seems to be what the Effect folks are calling this sort of thing) functions It does also appear here: https://github.com/Effect-TS/effect/blob/e0ef64102b05c874e844f680f53746821609e1b6/src/internal/defaultServices.ts#L25 to see the Random service (so basically, to seed the random number generator which one is expected to use in the context of an Effect computation, in order to have easy determinism for e.g. testing). But in this context (defining the schema) I don't see any reason why the Random service should be used; whereas in theory the Hash trait could be utilized sensibly here. And to be clear—this issue comes up anytime any Effect dependency is imported, so it makes the library unusable in the Convex schema.ts context
ian
ian14mo ago
Could both the library and schema.ts import table definitions from a shared module with no dependencies as a workaround?
em_errata
em_errata14mo ago
Don’t think that I have anything meaningful to contribute besides sharing that I’ve also experienced this with effect. Sorry if this is just noise, but the hope is to produce some data wrt how common/uncommon of an issue this is.
ballingt
ballingt14mo ago
Helpful to hear @em_errata, was this also for Schema?
em_errata
em_errata14mo ago
It was, yes.
ballingt
ballingt14mo ago
sorry and to clarify, also for schema.ts?
em_errata
em_errata14mo ago
No, that’s a good clarification! Yes, I was attempting to co-locate my validation logic within the schema module tree.
RJ
RJOP14mo ago
Possibly I’m not understanding your suggestion, but I think I’d have to do some codegen to make that sort of thing work. The flow is basically: - Create Effect Schema version of your Convex schema - Generate the Convex SchemaDefinition from the Effect Schema version Which means that there’s inevitably a dependency chain from Schema to schema.ts. I guess I could come up with some DSL for defining both schemas which depends on neither… but then that defeats a main purpose of this library!
ian
ian14mo ago
Gotcha. The minimum code schema.ts needs to import pulls in the Hash module. I thought there was a layer where Hash-related code could import from a schema def which could be shared with schema.ts. I'll leave it to Tom here
RJ
RJOP14mo ago
Alas no, but I appreciate the suggestion! For anyone interested, here's the full dependency chain: - User imports the Schema module - Which imports the Equal module: https://github.com/Effect-TS/schema/blob/1e115afab16c79841f683f73b51357805d8bf39e/src/Schema.ts#L11 - Which imports the Hash module: https://github.com/Effect-TS/effect/blob/e0ef64102b05c874e844f680f53746821609e1b6/src/Equal.ts#L5 - Which calls new PCGRandom() at the top-level: https://github.com/Effect-TS/effect/blob/e0ef64102b05c874e844f680f53746821609e1b6/src/Hash.ts#L16 - And PCGRandom (imported from Utils) uses Math.random() in its constructor: https://github.com/Effect-TS/effect/blob/e0ef64102b05c874e844f680f53746821609e1b6/src/Utils.ts#L541 Curious to know if there's a rough ETA for a fix here. I've been sorta holding off on working on theeffect-convex library further until this gets resolved. Is this the sort of thing I could expect to be supported on a timescale of a couple weeks, or a couple months (or other)?
ballingt
ballingt14mo ago
Let's say weeks, I posted a PR for it last week but @lee had some good suggestions for it I haven't implemented yet regarding how we treat the random seed — nothing big, I've just been having a good time focusing on a another project
RJ
RJOP14mo ago
darn you @lee and your commitment to high-quality engineering!
RJ
RJOP13mo ago
but seriously sounds great, thank you! As of the latest Convex release, I'm no longer blocked by Math.random limitations, but am now encountering into this issue: https://discord.com/channels/1019350475847499849/1157442906332856381 I'm of course importing Schema in my convex/schema.ts file, like so:
import { Schema } from "@effect/schema";
import { Schema } from "@effect/schema";
And also an additional 250 lines of library code (../../src/schema). The whole convex/schema.ts file looks like this:
import { Schema } from "@effect/schema";

import { defineEffectSchema, defineEffectTable } from "../../src/schema";

export default defineEffectSchema({
notes: defineEffectTable(
Schema.struct({
content: Schema.string,
})
),
}).schemaDefinition;
import { Schema } from "@effect/schema";

import { defineEffectSchema, defineEffectTable } from "../../src/schema";

export default defineEffectSchema({
notes: defineEffectTable(
Schema.struct({
content: Schema.string,
})
),
}).schemaDefinition;
ballingt
ballingt13mo ago
Sorry about this RJ and thanks for reporting as you explore this direction. What you're doing is reasonable and we'll look at supporting it tomorrow. So far we've encouraged folks to make the schema bundle as small as possible so hadn't hit this much but this is not a requirement, we can change it. @RJ This is resolved, the bundle produced from schema.ts has the same limits as the regular code bundle.
RJ
RJOP13mo ago
Thanks @ballingt! I'll report back when I have some time to try it out The latest error; pretty self-explanatory I think:
400 Bad Request: Error: Hit an error while evaluating your schema:
Uncaught Error: Date unsupported when evaluating schema
400 Bad Request: Error: Hit an error while evaluating your schema:
Uncaught Error: Date unsupported when evaluating schema
Would you be willing to give uses of Date the same treatment as for Random in queries and mutations?
ballingt
ballingt13mo ago
Hmm maybe we can add importing @effect/schema in a schema to our test suite to ensure this works! Yes this can get the same treatment.
RJ
RJOP11mo ago
Could pair with a warning like:
It looks like code in your schema file, or one of its dependencies, uses methods from the Date object. This may not be a problem, but do note that when you deploy your Convex schema, Date.now() will be set as the time your schema was deployed, and will not change thereafter.
Yeah that would be great, that's a much shorter feedback loop 🙂 Did this ever happen @ballingt? I'm on the latest version and am still seeing this error come up!
ballingt
ballingt11mo ago
That's looks right RJ, checking in now about when we could slip this in.
RJ
RJOP11mo ago
Sorry to pester you @ballingt, but if you could let me know once you have some idea when this might be shipped, I would really appreciate it! I have a bit more free time now than I have in the last couple of months, and am eager to work on this more 🙂
ballingt
ballingt11mo ago
Absolutely will!
RJ
RJOP10mo ago
Friendly bump 🙂
ballingt
ballingt10mo ago
RJ, I'm thinking about this but not actively working on it
RJ
RJOP9mo ago
No problem @ballingt, appreciate you checking in 🙇‍♂️ I got this far enough along last month that I think I could ship a v0.1, if I could test it/import Schema in convex/schema.ts, so I'm just excited to give that a shot! But no stress, I'm sure y'all have lots of other more important things to get done Turns out that for testing, at least, I can just do
Date.now = () => 0;
Date.now = () => 0;
😶
The Aleks
The Aleks8mo ago
Just wanted to give a big upvote to this one here @jamwt. While waiting for components, Effect-TS has significantly simplified my async workflows in Convex I don't understand the complexity of what needs to be done here and know you guys have a lot on your plate though 🙏 It works fine as is, but I'd love to see @RJ continue his work so I can swap out zod for Effect schemas 🎉
No description
Indy
Indy8mo ago
Date is now supported at Schema evaluation time. We haven't tried Effect yet, but hopefully it removes one more impediment. This was purely serverside, so you won't need to update the npm package. From our internal PR notes: "set Date.now to a fixed timestamp determined at the beginning of schema evaluation"
RJ
RJOP8mo ago
Fantastic, thanks @Indy et al.! I'll try it out soon and report back Resolved!
Indy
Indy8mo ago
Excellent work!
The Aleks
The Aleks2mo ago
@RJ did you end up writing some helpers for using Effect (and effect schema) with Convex?
RJ
RJOP2mo ago
I have! You can check it out here. I'm still considering it an alpha for now (I'm still not entirely satisfied with the DX and documentation in some areas), but I've begun using it in my own project. If you wanted to give it a try, I'd love any feedback!
The Aleks
The Aleks2mo ago
This looks pretty great! I’m excited to dig in now that I’m back in Convex @RJ why do we have to explicitly define return types? Couldn't we infer those?
RJ
RJOP2mo ago
Sort of; there are mainly two reasons why it's always required to add a Schema for returns validation: 1. It's more secure, because a) you can be sure that, by modifying a Confect/Convex function, you don't accidentally begin exposing additional data that you shouldn't be, and b) since TypeScript doesn't support exact types, it's possible to return data that's not reflected in the inferred return type 2. If you want to return e.g. an Effect type like Option, you need to serialize it as it crosses the wire, so we need to know how to do that. If you just try to return values like an Option without doing so, things might not work how you expect them to (or at all) If you haven't noticed already, you can pull the Schemas for your DB schema like so: https://github.com/rjdellecese/confect/blob/a5913f04524a0431b25edd9701ff9cb70f8d7497/test/convex/functions.ts#L19 In case that makes things easier
The Aleks
The Aleks2mo ago
2. Is what would require it I imagine. I wasn’t planning on returning anything but serializable types though - which would also allow me to work with the standard convex clients (and the ones for start).
RJ
RJOP2mo ago
I guess if you are aware of the risks and stay away from trying to return types like Option then it's technically not required When you say "standard Convex clients" do you mean you just want to write your frontend exactly the same as you would without Confect (e.g. don't worry about decoding return values, maybe don't even use Effect in the client)?
The Aleks
The Aleks2mo ago
I'm setting up my current project with TanstackStart and using the Tanstack Query integration. I'll use Effect on the client, but I'm okay expecting serialized values from the server and then just picking it up fromt here I like the idea of doing effect through and through, but the maintenance overhead of that seems pretty steep. Especially with the upcoming "local first" and "tanstack" apis
RJ
RJOP2mo ago
You're referring to the need to separate the args/returns schemas and reference them when invoking the function, like here, yeah? https://github.com/rjdellecese/confect/blob/a5913f04524a0431b25edd9701ff9cb70f8d7497/example/src/App.tsx#L93-L97 Just want to make sure I'm not missing some other pain point(s) Assuming so I definitely agree, it's pretty tedious But You don't need to use these @rjdellecese/confect/react helpers if you don't want to You can just use the exposed Convex functions like normal, with TanStack Query or whatever else uses the vanilla APIs, if you don't need/want to do any deserializing in the client Or you can do it later I do also plan on making this better in the future, it's just a bit more involved because I'll need to do some codegen And I'd like it to be integrated with TanStack Start, at a minimum, because that's what I'll be moving my project over to 🙂