Skip to content

Troubleshooting

Symptom Typical stderr / response Fix
hedron: command not found zsh: command not found: hedron python -m hedron … or below
Wrong interpreter ModuleNotFoundError: No module named 'hedron' Activate venv; pip install -e . / uv sync
Port busy ERROR: [Errno 48] Address already in use --port 8001 or stop the other process
CSRF 403 HTTP 403 on POST GET the form page first; FastAPI/Flask: csrf_token; Django: csrfmiddlewaretoken
HTMX 403 HTTP 403 on fragment Fix HX-Target to a declared region id/selector

hedron: command not found

Cause: The hedron console script is not on your shell PATH, or you installed into a different Python than the one your shell uses.

Always-works first: call the module with the same interpreter you used for pip:

python -m hedron new my-hedron-app
python -m hedron check

Other fixes:

  1. Re-open the terminal after install (PATH updates often need a new shell).
  2. Prefer uv tool install "hedron>=1.0.0" (or pipx install "hedron>=1.0.0") so the tool is on PATH, then run hedron new ….
  3. Inside a scaffolded project, use the project environment: uv run hedron check (or activate .venv and run hedron / python -m hedron).
  4. On Windows, add the install’s Scripts directory to PATH, or call the full path to hedron.exe.
  5. Verify the package with the same interpreter as uvicorn:
python -c "import hedron; print(hedron.__version__)"

If that fails with ModuleNotFoundError, activate the correct venv and reinstall (pip install -e . / uv sync). See also FAQ.

FastAPI version conflict on install

Symptom: pip / uv reports a resolver error, ResolutionImpossible, or an unexpected FastAPI/Pydantic version after install.

Cause: Another package pins FastAPI/Pydantic outside Hedron’s declared range (fastapi>=0.121.0,<0.150, pydantic>=2.12.0,<2.15), or you need the CI-supported band for a known-good first app (fastapi>=0.121.0,<0.142, pydantic>=2.12.0,<2.14). Declared ranges are wider than Supported — versions outside Supported can still install but are not CI-proven.

Fix: Create a clean virtual environment for the Hedron app (do not reuse a shared env that already pins an older FastAPI). Install only Hedron + uvicorn first (hedron>=1.0.0), then add other dependencies. For first apps, prefer staying inside the Supported band. See Compatibility.

Wrong interpreter or ModuleNotFoundError for hedron

Cause: uvicorn or python is from a different environment than the one where you installed Hedron (global vs venv, or forgotten pip install -e . after hedron new).

Fix: Activate the project venv, run pip install -e . or uv sync, then python -c "import hedron; print(hedron.__version__)" before starting uvicorn.

Blank page / HTMX or CSS not loading

Cause: Hedron static assets (/hedron-static/) or app assets are not reachable—wrong host/port, reverse proxy stripping paths, or a plain FastAPI app that never called mount_hedron_static.

Fix: With the Hedron() app facade, static mounts are automatic. For plain FastAPI, call mount_hedron_static(app). Confirm http://127.0.0.1:8000/hedron-static/ returns assets while the server runs. Behind a reverse proxy, forward /hedron-static/ and /hedron-assets/ unchanged. See Deployment and Plain FastAPI.

Port already in use (Address already in use on :8000)

Cause: Another process is bound to port 8000.

Fix: Stop the other server, or run uvicorn app:app --reload --port 8001 and open that port in the browser.

Wrong or unexpected version

Symptom: Features in the docs are missing from your install, or verify text does not match.

Fix: Check python -c "import hedron; print(hedron.__version__)". Expect the 1.0.x train in a PyPI-installed application and from the repository checkout. Upgrade an application with pip install -U "hedron>=1.0.0"; use uv sync only inside the repository. See What's ready. If docs describe a feature missing from your install, either upgrade toward the pin that matches this documentation or switch the docs to the tag that matches your installed release.

CSRF 403 on POST (FastAPI / Flask)

Cause: Missing or mismatched CSRF token/cookie.

Fix: Perform a safe GET first to receive hedron_csrf, then send X-CSRF-Token (or form field csrf_token) with the same value. On HTTPS, ensure the client stores Secure cookies. See Security.

Tutorial code does not match hedron new

Cause: A guide still shows an older region spelling, but hedron new generates @app.view("/status") and status.refresh_button(...).

Fix: Keep the generated app. Add a second @app.view as in HTMX interactions. Do not paste a region/fragment scaffold over Hello. See Which interaction API?.

HEDRON_SESSION_SECRET did nothing

Cause: Hedron does not read that environment variable. It is an adopter convention.

Fix: Pass session_secret= into Hedron(...), typically session_secret=os.environ.get("HEDRON_SESSION_SECRET", "replace-in-production"). See Secrets and workers.

HTMX 403 on fragment request

Cause: The request’s HX-Target is not in the route’s declared region allowlist (typo in the region id / selector, or wrong fragment route).

Fix: Prefer the generated handle: @app.view("/status") plus status.refresh_button(...). If you use the explicit allowlist path, keep one region object end-to-end: status = app.region("service-status"), RefreshButton.for_region(status, href="/status", ...), and @app.view("/status", fragment_regions=(status,)). Confirm with:

curl -H 'HX-Request: true' -H 'HX-Target: #service-status' http://127.0.0.1:8000/status

Try it (simulated)

Correct target swaps; wrong #panel returns 403 with no swap. Docs simulation.

Allowlist probeRegion #service-status is declared on the route.

Fail-closed: undeclared HX-Target never swaps.

Minimal runnable app.py that reproduces this demo (real Hedron, not the docs simulator):

app.py
import os

from hedron import Hedron, Page, Stack, html, swap

app = Hedron(
    title="Allowlist 403",
    security="standard",
    explorer="off",
    session_secret=os.environ.get("HEDRON_SESSION_SECRET", "dev-only"),
)

status = app.region("service-status", description="Status panel")


def status_panel():
    return html.div(
        html.strong("Service healthy"),
        html.span("Allowlisted #service-status"),
        id=status.id,
        role="status",
    )


@app.page("/")
def home() -> Page:
    return Page(
        Stack(
            status_panel(),
            html.button(
                "Correct #service-status → 200",
                type="button",
                **{
                    "hx-get": "/status",
                    "hx-target": status.selector,
                    "hx-swap": "outerHTML",
                },
            ),
            html.button(
                "Wrong #panel → 403",
                type="button",
                **{
                    "hx-get": "/status",
                    "hx-target": "#panel",
                    "hx-swap": "outerHTML",
                },
            ),
        ),
        title="Allowlist",
    )


@app.view("/status", fragment_regions=(status,))
def refresh():
    return swap(status_panel())

See HTMX interactions.

CSRF 403 on Django POST

Cause: Django CsrfViewMiddleware rejected the token, or the header name does not match settings.

Fix: Seed the cookie with a safe GET through HedronDjango.respond / hedron_view. Send Django's X-CSRFToken or set CSRF_HEADER_NAME = "HTTP_X_CSRF_TOKEN" and send Hedron's portable X-CSRF-Token. Form field must be csrfmiddlewaretoken. Django's CsrfViewMiddleware does not accept Hedron's portable csrf_token name. See Django quickstart and Security.

Explorer 404 or missing in production

Cause: explorer="off", missing hedron[dev], or production forced development mode off.

Fix: Install hedron[dev] for local Explorer; use explorer="development" only locally; open http://127.0.0.1:8000/hedron-explorer/ (trailing slash); use secured with auth in rare cases; keep production off.

hedron new installs an old train

Cause: An old CLI wrote hedron>=0.4.0 (or another pre-0.11 floor).

Fix: Edit pyproject.toml to hedron>=1.0.0 and uvicorn[standard]>=0.30, then reinstall. Current hedron new scaffolds hedron>=1.0.0 automatically.

SSE / WebSocket / preload not working

Cause: Using Flask/Django expecting FastAPI live helpers; proxy buffering SSE; preload left disabled; Origin rejected; treating experimental live APIs as production-required.

Fix: Live helpers (job_status_sse_response, accept_page_session_channel, NavigationPreloadPolicy) are FastAPI experimental surfaces (hedron.experimental) — prefer polling on every host, including FastAPI. Disable response buffering for text/event-stream. Enable preload only with an explicit NavigationPreloadPolicy(enabled=True). Maturity source of truth: What’s ready.

Production startup: missing manifest (HED-BUILD-0003)

Cause: HEDRON_ENV=production / production=True without hedron build output.

Fix: Run hedron build and set HEDRON_BUILD_DIR if the manifest is not at .hedron/build/manifest.json. Quickstarts do not create a production manifest—build before setting production mode.

Cannot import Auto / DataTable / chart helpers

Cause: Auto is core (from hedron import Auto). DataTable / DataEditor need the data extra. First-party charts require hedron[charts] on the same pin as the rest of Hedron (>=1.0.0).

Fix:

# Auto needs no extra
pip install "hedron[data]>=1.0.0"      # DataTable, DataEditor
pip install "hedron[charts]>=1.0.0"   # chart components

The old hedron-charts 0.1.x line is incompatible with current Hedron. See Compatibility, Installation, and charts and HTMX.

NodeLike import error from hedron

Cause: NodeLike lives in hedron_core.

Fix: from hedron_core import NodeLike (or avoid naming it and return built-ins).

Mounted app / reverse proxy broken URLs

Cause: ASGI root_path or WSGI SCRIPT_NAME not applied; absolute reverse URLs prefixed wrongly.

Fix: Configure your proxy/root_path correctly. Flask reverse forces path-only URLs before applying prefixes—see adapter tests and Architecture.

Redis / jobs optional

Cause: Compose examples set HEDRON_REDIS_URL for optional job backends.

Fix: Redis is not required for basic pages. Omit the variable unless you configure a job backend that needs it. See CONFIGURATION.

Flask async view RuntimeError

Cause: Flask async views need the optional async extra (greenlet).

Fix: Install Flask's async extra, or keep sync views (Supported sync-only path).

Still stuck?

Open a GitHub issue with Hedron version, command/traceback, host framework (FastAPI / Flask / Django), and whether HEDRON_ENV is set. Check FAQ, Error codes, and Support first. Report vulnerabilities privately via SECURITY.md.

Auth 401 forever

Cause: A require_user dependency reads session["username"], but no login route ever sets it.

Fix: Follow Authentication (login/logout with CSRF), or use the reference app’s HTTP Basic pattern.

HTMX form attrs typing

Cause: Hyphenated HTMX attribute names (hx-post, …) must be passed via a dict unpacked into Form(...).

Fix: Build a dict[str, str] with the required values (see Forms and actions) or use html.form(...) as in minimal form. A # type: ignore on the unpack is rarely needed when the dict is annotated.