Skip to main content

Troubleshooting and compatibility

The node's failure modes are designed to be nameable. Work from the signal you see.

Mesh: unavailable

status().mesh reports { state: "unavailable", reason: … } when the native transport could not load; the Jazz server still runs LAN-only and ticket()/pair() throw MeshUnavailableError rather than degrade silently. Causes, in resolution order:

  1. An explicit LOFI_NODE_IROH path that doesn't exist.
  2. Running from source without building the native layer (cargo build --release in native/iroh-js).
  3. An unsupported platform — most notably Windows, a documented gap (the *-gnu build path needs a libnode.dll import library the upstream toolchain ships only for msvc). Windows nodes run LAN-only until that resolves.

On arm64 Linux the limitation sits one layer deeper: the Jazz engine (jazz-napi) publishes no linux-arm64-gnu build, so the node cannot start at all there. Release binaries and the container image cover macOS arm64 and Linux x86_64 (platform notes).

The compiled binary embeds digest-pinned prebuilts; a cache extraction that doesn't match its pin fails loudly rather than loading.

401 invalid_ticket

Unknown ticket, revoked ticket, or a sync-scoped ticket on an admin route — deliberately one answer for all three. If a previously working app starts seeing it, the ticket was revoked: re-enroll with a fresh one. If provisioning sees it, the ticket lacks provision scope.

WebSocket closes with 4001

The ticket was revoked mid-session. This is the live-revocation path working as designed; the app should treat its stored sync location as dead and surface re-enrollment, not retry.

502 store_unavailable

The gate is up but its store is not — the loopback Jazz process, or on a leaf, the tunnel to the root. Check lofi-node status and, for a leaf, status().mesh.connections.

Writes hang; nothing errors

Almost always a store with no deployed schema — the engine hangs rather than fails in this state. GET <ticket-url>/store-status reporting { "deployed": false } confirms it; the remedy is provisioning. lofi apps classify before attaching sync for exactly this reason.

Version mismatch

A node must run the same Jazz alpha as the apps it serves. Mismatches surface as protocol-level failures (schema hash and catalogue errors) that no network configuration fixes. Confirm both pins before debugging anything else.

Compatibility status, honestly

The whole flow is validated end to end against lofi's reference app with real browser clients: build, boot, offline edits, reconvergence, and the full provisioning lifecycle through the gate and through an iroh-paired leaf. One known upstream finding: lofi's opt-in browser convergence gate fails at its final stage with a catalogue error identically against lofi-node and against lofi's own first-party dev server — a controlled experiment placing the issue in the pinned Jazz alpha, not the node. lofi-node's contract docs carry the current validation table.