Preview diagnostics

This page is for developers working on the Oda codebase. A running browser preview writes to the browser console from two sides, the page and its worker, and its shell reports command output of its own. This page collects the messages a preview run prints and says where each one appears, what it means and what to do. Starting the preview and how it boots is on Browser preview; command behaviour is on The preview shell; what the preview does not carry is on Preview limitations.

In the tables, <...> stands for a value from the run, such as a path, a status or an id. Console lines also start with a label that names the side that wrote them; the tables quote each message after that label.

Where the preview prints messages

Only warnings and errors are forwarded from the running application; everything else is dropped on purpose, because the running application produces far too much of it. A forwarded line starts with the name of the component that wrote it. For example, the skill registry can warn about a provider it skipped: skill: rendered(provider "local" skipped: FS_IO_ERROR). A provider that fails and is skipped would otherwise look the same as one that found nothing, so the warning explains a list that came up empty where content was expected.

Page console messages

MessageAppears inWhat it meansWhat to do
tunnel: unsupported request body <kind>Page consoleThe connector cannot carry the body a caller gave it; only byte buffers, Blobs and read streams can cross.Send one of those; strings and byte views are converted for you, anything else is refused.
tunnel: worker failed: <message>Page consoleThe worker raised an uncaught error; every request still in flight fails with this message.Read the worker's own error first; that is the failure to fix.
tunnel: boot payload failed with HTTP <status>: <body>Page consoleThe request for the page's boot payload failed; the body carries the server's answer.Fix the response; the page cannot finish starting without the payload.
tunnel: bundle <url> failed with HTTP <status>; tunnel: bundle <url> failed to executePage consoleA client bundle could not be fetched, or it arrived and threw while loading.Check the bundle's address and that the image carries it; the bundle's own console error is the real loading failure.
tunnel: unknown frame <frame>Page consoleThe worker sent a frame kind this build does not recognise.The two sides come from different builds; rebuild them together.
tunnel: request <id> <method> <url> → HTTP <status>: <message> (warning)Page consoleA response arrived with a status of 500 or above; a lower status is answered without a warning. During boot, requests wait, and a boot that fails answers them with HTTP 503 and a plain-text reason that renders one line per nested cause.Read the text after the status; it is the worker's rendered failure. The warning names the connector as the reporter, and the status may equally have come from the application's own routes.

Worker console: connector messages

MessageAppears inWhat it meansWhat to do
tunnel: message is not a frame: <value>Worker consoleA message from the page is not a frame at all.Check what was posted; only the connector's frames travel here.
tunnel: init frame needs a string image url; tunnel: init frame needs an array of string overlay urlsWorker consoleThe start message is missing its image address or its overlay list.Fix both fields; the worker entry refuses the same pair before the host is built.
tunnel: frame has no usable id: <value>; tunnel: unknown frame type <type>Worker consoleA frame has no id to answer, or its kind is not one this build knows.Fix the frame against the current contract.
tunnel: stream <id> needs a non-empty endpointWorker consoleA stream was opened without an endpoint.Name the endpoint the stream should open.
tunnel: request <id> needs string method and url; tunnel: request <id> needs a headers object; tunnel: request <id> body must be an ArrayBuffer, Blob, or ReadableStreamWorker consoleA request frame is missing its method, its address, its headers, or carries a body kind that cannot cross.Fix the named field; the refusal says which one failed.
tunnel: duplicate init frame; the tunnel is already openWorker consoleA second start message arrived at a running connector and is ignored; the first one owns the tunnel.Only one start message per worker; look for a double connect.
tunnel: serving (unary /api lane=<lane>, privileged set=<count>, queued=<count>) (info)Worker consoleThe application is serving; the count shows how many requests were waiting in the boot queue, and they dispatch now.Use it as the boot checkpoint.
tunnel: route lane refused <method> with <status>; answering on the direct laneWorker consoleA call that needs the worker's own access was first refused with 401 or 403 by the route table; it is retried once on the direct path.Expected for calls that need the worker's own access.
tunnel: Remote stream requested before the host tree is serving; tunnel: boot payload requested before the host tree is serving; tunnel: direct fetch requested before the host tree is servingWorker consoleWork that needs the booted application arrived while it was still booting; these guard the boot order.During a normal boot, requests queue and do not print these; if one appears, work was dispatched before the serving line.
tunnel: stream uplink has one pending readWorker consoleA second read overlapped a read already pending on a stream's uplink.Keep one reader per uplink.

Worker console: boot, image and filesystem messages

MessageAppears inWhat it meansWhat to do
host: no channel; pass options.channel outside a dedicated worker; host: no message source; pass options.channel outside a dedicated workerWorker consoleThe assembly found no message channel, or no message source to listen on.Start the host from the worker entry, or pass the channel explicitly.
host: image fetch failed with <status> for <address>; host: image response for <address> carried no bodyWorker consoleThe image could not be fetched, or the response carried no bytes.Check the address and what serves it; the image itself must come back.
host: <path> is missing, so the image records no lowering; rebuild the imageWorker consoleThe image lacks the marker that says it was prepared for this runtime; the worker holds no compiler, so it cannot recover it.Repack the image with the current build.
host: image was lowered by <recorded>, this build runs <expected>; rebuild the imageWorker consoleThe image was prepared by a different build.Repack the image with the current build.
host: the tree activated without a Connection service; host: the tree activated without a typertGateway service; host: no webServer service, so the page cannot receive its boot injectionsWorker consoleThe application started but a service it needs is missing; the first two stop the tunnel from serving, the last stops the page's boot payload.Find why the named service did not start; without it the preview cannot serve.
host: the tree was disposedWorker consoleThe host was stopped; waiting and later requests are refused with this reason.Expected on shutdown.
host: tree requested exit(<code>) (warning)Worker consoleSomething asked the application to exit; the preview cannot stop that way, so the request is logged and the worker keeps running.Use the preview's own stop path rather than an exit call.
host: tree active (modules=<count>, data overlays=<count>, direct lane=<...>, als causality=<...>, image lowering=<...>) (info)Worker consoleThe application is up, and the line names what it activated with.Use it as the boot checkpoint.
image: <source> is not the gzip-compressed tar this deployment serves as its image (expected a member starting 1f 8b, read <bytes>); a host that answered with a Content-Encoding the transport already decoded, or a build that wrote the archive uncompressed, arrives exactly this wayWorker consoleThe bytes served at the image address are not the packed image. A server that answered with a page reads read 3c 21 64 6f 63 74 79 70; a truncated start reads read 1f.Serve the image file itself; if the build wrote the archive uncompressed, repack it.
image: <source> produced no readable bodyWorker consoleThe image bytes were empty or unreadable.Fix what serves the image.
vfs: image entry must be relative to <root>, received "<name>"Worker consoleThe packed image holds an entry that escapes the mount root; the packing step should have refused it.Repack the image, or fix the entry the archive carries.
vfs: overlay entry must stay under home or workspace, received "<name>"Worker consoleAn overlay tried to write outside the two data folders; overlays cannot replace program files or configuration.Fix the overlay's paths; see Preview fixtures and sample data.
vfs: overlay file cannot replace directory "<target>"Worker consoleAn overlay file landed where the mounted image already holds a directory.Fix the overlay so the two do not collide.
vfs: no filesystem is mounted; the worker entry must call setActiveVfs before any node:fs accessWorker consoleCode touched the filesystem before the image was mounted.Mount the image before any filesystem use.
process: exit(<code>) requested; the worker keeps running; kill ESRCHWorker consoleA process exit call is logged and cannot stop the worker; a signal was sent to a process id the worker is not running.Use the preview's stop path; commands run with process ids above the worker's own.

Build output: module preparation

MessageAppears inWhat it meansWhat to do
transform: <detail> (<path>:<line>)Build outputThe shape of every refusal below; each one names the file and the line.Fix the source pattern or its wiring, then repack.
import attributes are not supportedBuild outputA module uses import attributes, which the preparation step does not support.Rewrite the import without attributes.
the module is already lowered; check the image manifest wiringBuild outputA module was prepared twice; the wiring packed an already prepared body.Fix the manifest wiring and repack.
top-level await cannot run as CommonJS in the worker; a top-level for-await loop cannot run as CommonJS; a labeled for-await loop is not supportedBuild outputA module uses top-level await or a top-level for-await loop, which cannot run in the worker.Move the work into a function instead of the module's top level.
yield* is only supported as the whole statement expressionBuild outputA yield* form the preparation step cannot rewrite.Use yield* as the whole statement.
the transform produced code that does not parse: <message>Build outputThe prepared body no longer parses; the detail carries the parser's message.Record the file and line and report it; the preparation step produced output that does not parse.

Worker console: module loading messages

MessageAppears inWhat it meansWhat to do
modules: <detail> (importer chain: <a -> b -> c>)Worker consoleThe loader failed; the chain lists the modules that led to the failure.Read the chain to find the requesting code, then read the detail after it.
cannot resolve "<specifier>": no file at <candidates>; cannot resolve "<specifier>": <path>/package.json is not in the imageWorker consoleA module cannot be found inside the image: no file at the tried paths, or the package's manifest was not packed.Check the packed dependency and its paths, then repack.
"<package>" does not export "<subpath>" under conditions [<conditions>]Worker consoleThe package does not offer that entry under the resolution conditions the worker uses.Import an entry the package exports for the browser-oriented conditions.
"<specifier>" is a worker-provided module and has no VFS pathWorker consoleThe name resolves to the worker's own module table, so there is no file path to point at.Expected for the worker's own modules; for anything else, check what is packed.
<path> still carries module syntax, so the image was not lowered by the packer (<reason>); rebuild the imageWorker consoleThe image holds a module the preparation step did not prepare; a top-level await body reads a similar message.Repack the image with the current build.
modules: no loader is mounted; the worker entry must call setActiveModuleLoader before any createRequire useWorker consoleModule resolution ran before the loader was mounted.Mount the loader before module use.
als: for-await source is neither async nor sync iterableWorker consoleA for-await loop was given something that cannot be iterated.Fix the loop's source.

Messages a command or caller sees

These are not console lines of their own: they are raised to the code that made the call, and they surface wherever that code logs or reports them.

MessageAppears inWhat it meansWhat to do
spawn <program> ENOENT (with code ENOENT)CallerA start was attempted for a program the preview does not have; only the preview's own command table can run, so anything else fails exactly like a missing binary.Use a command the table has; see The preview shell.
node:child_process.spawnSync cannot run <program> in the worker host: commands run asynchronouslyCallerA synchronous start cannot run a command; only the asynchronous path can.Start the command asynchronously and read its result from the handle.
Command failed: <command line>CallerA command line started through the callback-style path ended with a failure.Read the output and status carried with the error.
The "file" argument must be a non-empty string. Received <value> (code ERR_INVALID_ARG_TYPE)CallerThe program name was missing or not a string.Pass a non-empty program name.
The operation was aborted (name AbortError, code ABORT_ERR); The operation was aborted. (timers)CallerAn abort signal was triggered, so the operation stopped by design.Expected when you cancel; an aborted command run settles as exit code 130 with no output of its own.
EBADF: bad file descriptor, <operation>CallerA file operation used a descriptor that is not open.Open the file first and close it after use.
EEXIST: file already exists, open '<path>'CallerAn exclusive create found the file already there.Pick another name or drop the exclusive flag.
The "callback" argument must be of type function; The value of "start" is out of rangeCallerA callback-style call was given no callback, or a read or write started outside the file.Pass a callback, or use the promise face; check the offsets against the file's size.
The argument 'flags' is invalid. Received '<flags>' (code ERR_INVALID_ARG_VALUE); The value of "len" is out of range. It must be >= 0. Received <value> (code ERR_OUT_OF_RANGE)CallerAn open-flags combination the preview cannot accept, or a resize length that is negative or not a whole number.Use r, w or a with the +, x and s modifiers; pass a non-negative whole length.

Questions, answered

Where do the preview's messages appear?

In the browser console from two sides (the page connector and the worker), in the shell's own output for a command run, and in the packing step's output while an image is prepared. The tables above say which for each message.

Why does a failed request warn on the page console?

The connector warns when a response arrives with a status of 500 or above, naming the request and the answer, so a failure that left no other trace stays visible. A route's own 4xx answer is returned without a warning.

Why did a request come back as HTTP 503 while the preview was starting?

During boot, requests wait in a queue. A boot that fails answers them with HTTP 503 in plain text and the rendered reason, one line per nested cause; fix the failure the text names, then reload.

Why does the preview say the image is not the gzip-compressed tar?

The bytes served at the image address are not the packed image, so nothing can be mounted. Check that the address returns the image file itself (a page served instead reads read 3c 21 64 6f 63 74 79 70), and repack if the build wrote the archive uncompressed.

What does the importer chain in a module message tell me?

It lists the modules that led to the failure, in order, so you can find the requesting code; the detail after it names what went wrong, such as a file that is not in the image or an export the package does not offer under the worker's conditions.

Why does starting a program from preview code fail with ENOENT?

Only the preview's own command table can run. Anything else fails exactly like a missing binary, reported as spawn <program> ENOENT with the code ENOENT. Use a command the table has; see The preview shell.

Why did an operation fail with The operation was aborted?

An abort signal was triggered, so the call stopped by design. It is the normal result of cancelling; an aborted command run settles as exit code 130 with no output of its own.

Why was a request body refused?

Bodies must be byte buffers, Blobs or read streams before they can cross between the page and the worker; anything else is refused with tunnel: unsupported request body. Convert the value first.

Why do I see only some of the application's messages in the console?

Only warnings and errors are forwarded; everything else is dropped on purpose, because the running application produces far too much of it. A forwarded line starts with the name of the component that wrote it, which tells you where to look.

What does overlay entry must stay under home or workspace mean?

An overlay tried to write outside the two data folders. Overlays cannot replace program files or configuration; fix the overlay's paths. See Preview fixtures and sample data.

Why does the worker say the tunnel is already open?

A second start message arrived at a running connector and was ignored; the first one owns the tunnel. Look for a double connect or a second start.