Debugging playbook#
This page is a step-by-step debugging runbook for Cellucid Python developers and power users.
It is optimized for two outcomes:
you can fix the issue yourself, or
you can file a bug report that a maintainer can act on without guessing.
Step 0 — Identify which mode you are in#
Everything downstream depends on this.
Pick the closest match:
Mode A: Export folder#
you ran
cellucid.prepare(...)and have a directory export.you start the viewer with
cellucid serve ./export_dirorcellucid.show("./export_dir").
Mode B: AnnData server#
you are serving
.h5ad/.zarror an in-memory AnnData.you start the viewer with
cellucid serve ./data.h5adorcellucid.show_anndata(...).
Mode C: Notebook embedding#
you are in Jupyter/VSCode/Colab.
you see an iframe (or a blank output where you expected an iframe).
Step 1 — Confirm the server is alive#
Open a terminal (or use curl from wherever the server is running) and check:
curl -s http://127.0.0.1:8765/_cellucid/health
curl -s http://127.0.0.1:8765/_cellucid/info
If these fail:
your server is not running, crashed, or the port is wrong.
If the port differs, find it in:
the CLI banner output, or
viewer.server_url(notebook), orserver.url(Python).
Step 2 — Confirm the viewer UI assets can load#
Open:
http://127.0.0.1:<port>/
If you see an error page “viewer UI could not be loaded”:
the hosted-asset proxy could not fetch the UI and no cached copy exists.
Fix options:
ensure network access to
https://www.cellucid.com,run once while online to populate the cache,
set
CELLUCID_WEB_PROXY_CACHE_DIRto a writable/persistent directory.
See: Server mode architecture, endpoints, and security and Configuration, environment variables, and logging.
Step 3 — Confirm dataset endpoints return data#
Export folder mode#
Check that the directory contains:
dataset_identity.jsonobs_manifest.jsonat least one
points_*d.binorpoints_*d.bin.gz
Then probe:
curl -I http://127.0.0.1:<port>/dataset_identity.json
curl -I http://127.0.0.1:<port>/obs_manifest.json
curl -I http://127.0.0.1:<port>/points_3d.bin
curl -I http://127.0.0.1:<port>/points_3d.bin.gz
(One of the two points paths should exist depending on compression.)
AnnData server mode#
Probe:
curl -I http://127.0.0.1:<port>/dataset_identity.json
curl -I http://127.0.0.1:<port>/obs_manifest.json
curl -I http://127.0.0.1:<port>/points_3d.bin
If you want to test gene/obs endpoints, pick a known key and try:
curl -I http://127.0.0.1:<port>/var/FOXP1.values.f32
curl -I http://127.0.0.1:<port>/obs/cell_type.codes.u8
Step 4 — Use browser DevTools (network + console)#
This is the fastest way to distinguish:
server failures (404/500),
format/schema issues (manifest parse errors),
and frontend/UI issues.
4.1 Network tab checklist#
In browser DevTools → Network:
filter for
_cellucid:/healthshould be 200/infoshould be 200
filter for
obs_manifest.jsonandvar_manifest.json:should be 200 and have JSON content
look for 404s:
missing
.gzfiles often means a partial export / compression mismatch
look for CORS errors:
“CORS blocked” usually means origin mismatch or a proxy issue
Use the browser Network tab to separate “server/format” problems from “UI” problems.#
4.2 Console tab checklist#
In DevTools → Console:
copy/paste the first relevant error (don’t paraphrase)
look for:
“Failed to fetch”
“CORS blocked”
JSON parse errors (manifest schema mismatch)
If you suspect web-app internal bugs, also consult:
Step 5 — Notebook-specific debugging (viewer.debug_connection())#
If you have a viewer object (Jupyter/VSCode/Colab), run:
report = viewer.debug_connection()
report
The report includes:
server health/info probes,
whether the viewer is displayed,
web UI cache status + build id,
a Python→frontend ping/pong roundtrip,
a frontend “debug snapshot” (URL/origin/userAgent as seen by the iframe),
and recent frontend console warnings forwarded to Python.
If you are filing a bug report, paste the report as JSON:
import json
print(json.dumps(report, indent=2, default=str))
Notebook debugging: viewer.debug_connection() consolidates server reachability, cache status, and frontend roundtrip checks into one report.#
Common failure patterns (fast diagnosis)#
Pattern: “Viewer UI loads, but data is missing”#
Export folder mode:
manifests might reference files that don’t exist (partial export)
safe-key mismatch (field names vs filenames)
.gzmismatch (exported compressed, but viewer requests uncompressed or vice versa)
AnnData server mode:
route for that path may not exist (wrong filename/ext)
adapter could be raising internally (check server logs)
Start with:
Pattern: “Hooks don’t fire”#
Confirm in browser Network tab:
POST /_cellucid/eventsis happening and returns 200.
If it is not happening:
frontend may not be configured for notebook mode,
iframe may be blocked by proxy/mixed-content issues.
If it is happening:
viewerId may mismatch (stale iframe vs new viewer),
Python viewer may have been stopped/garbage-collected.
Start with:
Pattern: “Everything works locally, fails on a remote server”#
Likely causes:
binding host incorrectly (
127.0.0.1vs0.0.0.0)missing SSH tunnel
corporate firewall
HTTPS notebook mixed-content
Fix:
prefer SSH tunneling over public binding,
or provide a stable reverse proxy and set
CELLUCID_CLIENT_SERVER_URL.
What to include in a high-quality bug report#
Minimum:
mode (export folder vs AnnData vs notebook)
cellucidversion + Python version + OSreproduction steps (code or click-by-click)
expected vs actual
server URL + what
/_cellucid/healthreturnsbrowser console error(s)
Notebook:
attach
viewer.debug_connection()report.