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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions