Guides - Troubleshooting

When calling client.enter(), you stumble upon the following error:

ReferenceError: process is not defined

The @liveblocks/client package expects to be consumed by a JavaScript bundler, like Webpack, Babel, ESbuild, Rollup, etc. If you see this error, you have most likely directly loaded the @liveblocks/client source code through a <script> tag.

If using a bundler isn’t possible for you, there are two available solutions.

One solution is to load the source code from the Skypack CDN, which will expose optimized production builds which have the process variable removed.

Another solution is to define the necessary process.env.NODE_ENV variable manually, before loading the script, for example:

globalThis.process = { env: { NODE_ENV: "production" } };

If you found this page, chances are you stumbled upon this TypeScript error:

1
2
3
TS2344: Type 'MyInterface' does not satisfy the constraint 'Lson'.
Type 'MyInterface' is not assignable to type 'JsonObject'.
Index signature for type 'string' is missing in type 'MyInterface'.

Liveblocks data structures (like LiveObject, LiveMap, and LiveList) require that their payloads are always JSON-serializable to be able to send them over WebSocket connections reliably and without surprises. Starting with 0.16, we’re enforcing this with Lson type constraint. (LSON is a Liveblocks-specific extension of JSON that also allows nesting more Live data structures.)

If you encounter this error above, TypeScript is trying to tell you that the data type you are using in one of your Live structures is not (guaranteed to be) a legal LSON (or JSON) value. But why?

1
2
3
4
5
6
7
8
9
interface Person {
name: string;
age: number;
}
const people = new LiveList<Person>();
// ~~~~~~
// TS2344: Type "Person" does not
// satisfy the constraint "Lson" ☹️

Although this Person type seems perfectly JSON-serializable with only those string and number fields, TypeScript still considers this a problem because it cannot guarantee that all of its subtypes will also be that. Interface types are "open" and extensible by design. This means it’s possible to define a subtype that would still not be JSON-serializable. Example.

To fix this issue, there are roughly three available solutions.

The simplest solution is to convert your interface to a type.

1
2
3
4
5
6
7
type Person = {
name: string;
age: number;
};
const people = new LiveList<Person>();
// ^^^^^^ ✅ All good now

Check this solution out in the TypeScript playground.

You can also explicitly pledge that your interface will be JSON serializable by having it extend from JsonObject.

1
2
3
4
5
6
7
8
9
import { JsonObject } from "@liveblocks/client";
interface Person extends JsonObject {
name: string;
age: number;
}
const people = new LiveList<Person>();
// ^^^^^^ ✅ All good now

Check this solution out in the TypeScript playground.

This is the least preferred solution, but may be necessary if you don’t own the interface definition and it’s coming from an external package.

1
2
3
4
5
import type { LiveList, EnsureJson } from "@liveblocks/client";
import { Person } from "some-external-package";
const people = new LiveList<EnsureJson<Person>>();
// ^^^^^^^^^^^^^^^^^^ ✅ All good now

Check this solution out in the TypeScript playground.