Skip to content

Bug: CoList.toJSON fails when list contains primitive values (strings) #3412

@ctwhome

Description

@ctwhome

Description

The toJSON method in CoList fails with TypeError: item?.toJSON is not a function when the list contains primitive values (like strings) instead of CoValues.

Reproduction

This occurs when using the Better Auth database adapter with debug logging enabled:

import { JazzBetterAuthDatabaseAdapter } from 'jazz-tools/better-auth/database-adapter';

database: JazzBetterAuthDatabaseAdapter({
  syncServer: `wss://cloud.jazz.tools/?key=${apiKey}`,
  accountID: workerAccountId,
  accountSecret: workerSecret,
  debugLogs: true  // <- triggers the bug
}),

Root Cause

In src/better-auth/database-adapter/repository/account.ts, the AccountIdIndex is defined as:

var AccountIdIndex = co.list(z.string());

This creates a CoList containing primitive strings.

When Better Auth logs with debug mode, it calls inspect() on Jazz objects, which triggers toJSON(). The CoList's toJSON method assumes all items are CoValues:

return this.map(
  (item, idx) => seenAbove?.includes(item?.$jazz.id) 
    ? { _circular: item.$jazz.id } 
    : item?.toJSON(idx + "", [...seenAbove || [], this.$jazz.id])
);

This code:

  1. Tries to access item?.$jazz.id - undefined for primitives
  2. Calls item?.toJSON() - fails because strings don't have a toJSON method

Error Stack Trace

TypeError: item?.toJSON is not a function
    at eval (jazz-tools/dist/chunk-HBWUGW37.js:1078:99)
    at Proxy.map (<anonymous>)
    at Proxy.toJSON (jazz-tools/dist/chunk-HBWUGW37.js:1077:19)
    at [nodejs.util.inspect.custom] (jazz-tools/dist/chunk-HBWUGW37.js:1088:17)

Suggested Fix

The toJSON method should check if items are primitives before calling .toJSON():

return this.map((item, idx) => {
  // Handle primitives (strings, numbers, booleans, null)
  if (item === null || typeof item !== 'object') {
    return item;
  }
  // Handle CoValues
  if (seenAbove?.includes(item?.$jazz.id)) {
    return { _circular: item.$jazz.id };
  }
  return item?.toJSON(idx + "", [...seenAbove || [], this.$jazz.id]);
});

Workaround

Disable debug logs in the adapter configuration:

debugLogs: false

Environment

  • jazz-tools: 0.20.6
  • better-auth: 1.4.17
  • Node.js / Bun runtime

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions