Qwik "Code ... captured ... but is not serializable" in CI
Qwik serializes state across the server/client boundary so it can resume without replaying JS. Inside a $ closure (component$, useTask$), every captured value must be serializable. Capturing a class instance, DOM node, or function throws at build or runtime.
What this error means
The build or a runtime check fails with "Code ... captured a value ... but it is not serializable", naming the variable captured inside a $ boundary.
Error: Code(QRL) that was dynamically imported "src/routes/index.tsx"
captured a value "logger" but it is not serializable:
[object Object] (class instance)Common causes
A non-serializable value captured in a $ closure
Class instances, functions, DOM references, and symbols cannot be serialized, so capturing them across a $ boundary fails.
A closure that should have been a QRL
Passing a bare function where Qwik expects a lazy $(...) boundary captures the function itself, which is not serializable.
How to fix it
Capture only serializable values
- Move non-serializable objects (loggers, clients) into the closure body instead of capturing them.
- Recreate them inside the
$function, or useuseStorefor serializable state. - Wrap callbacks in
$(...)so Qwik stores a QRL, not the raw function.
import { component$, useTask$ } from '@builder.io/qwik';
export default component$(() => {
useTask$(() => {
const logger = createLogger(); // created inside, not captured
logger.info('run');
});
});Keep state in useStore / useSignal
Store serializable primitives and plain objects in Qwik state containers so they cross the boundary cleanly.
import { useStore } from '@builder.io/qwik';
const state = useStore({ count: 0 });How to prevent it
- Capture only serializable data inside
$boundaries. - Create clients/loggers inside the closure, not outside it.
- Use
useStore/useSignalfor shared state.