Skip to content

ORM-hydrated Date objects crash t.run() return serialization in convex-test #96

@MyThunder11

Description

@MyThunder11

Problem

When using better-convex ORM inside t.run() (from convex-test), returning objects that contain timestamp() fields causes a serialization crash. The ORM correctly hydrates these fields as JS Date objects, but convex-test serializes t.run() return values through Convex's convexToJson, which does not support native Date objects.

Error

Error: Date "2026-02-24T17:23:11.922Z" is not a supported Convex type
(present at path .createdAt in original object {...}).

Reproduction

import { convexTest } from "../setup.testing";
import { withOrm } from "../lib/orm";
import schema, { organizationTable } from "./schema";

it("returns a Date object from t.run without crashing", async () => {
  const t = convexTest(schema);

  // This crashes ❌
  const result = await t.run(async (baseCtx) => {
    const ctx = withOrm(baseCtx);
    const [org] = await ctx.orm
      .insert(organizationTable)
      .values({ name: "Test", slug: "test", monthlyCredits: 100, ... })
      .returning();
    return org; // org.createdAt is a Date — convex-test can't serialize it
  });
});

Current workaround

We have to manually extract primitives or convert dates to strings inside every t.run:

const result = await t.run(async (baseCtx) => {
  const ctx = withOrm(baseCtx);
  const run = await ctx.orm.query.analysisRun.findFirst({ where: { id } });
  return {
    status: run?.status ?? null,
    completedAt: run?.completedAt?.toISOString() ?? null, // manual conversion
  };
});

This is tedious and error-prone — every test that reads ORM data inside t.run needs this boilerplate.

Expected behavior

Returning ORM-hydrated objects (with Date fields from timestamp() columns) from t.run() should work seamlessly. The ORM could dehydrate Date objects back to Convex-compatible values (e.g., number timestamps) before t.run serializes the return value.

Possible solutions

  1. Dehydrate in the ORM layer: Add a dehydrateDateFields() counterpart to hydrateDateFieldsForRead() that converts Datenumber (ms timestamp), and apply it automatically when the return value crosses the t.run boundary.
  2. Provide a helper: Export a toConvexValue(obj) utility that users can wrap their return values with.
  3. Patch t.run in convex-test setup: Override the serialization to handle Datenumber conversion (this might belong in convex-test itself rather than better-convex).

Environment

  • better-convex@0.6.0
  • convex-test@0.0.41
  • convex@1.32.0

Related

This is a follow-up to #93 which fixed .returning() with nullable timestamps and findFirst returning null. That PR fixed the production ORM behavior, but this serialization issue remains specifically in the convex-test testing context.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions