can1357/oh-my-pi · error · DashboardBundleMissing

frontend bundle at {_INDEX_PATH} is missing the {_CONFIG_SEN

Error message

frontend bundle at {_INDEX_PATH} is missing the {_CONFIG_SENTINEL} sentinel; rebuild with `bun run web:build`

What it means

`_load_index_template` found the frontend `index.html` but it does not contain the expected `_CONFIG_SENTINEL` marker string, so it raises `DashboardBundleMissing`. The sentinel proves the bundle was produced by the current build pipeline (which injects runtime config placeholders); an old, stale, or hand-made index.html without it cannot be configured correctly, so the library refuses to serve it.

Source

Thrown at python/robomp/src/dashboard.py:103

    Creates the directory lazily so a fresh checkout (or a runtime container
    that hasn't shipped the bundle yet) can still construct the app —
    `_load_index_template()` raises `DashboardBundleMissing` separately when
    the `index.html` itself is missing. Without this mkdir,
    `StaticFiles(directory=...)` would raise at app construction time and
    block every other route.
    """
    _STATIC_DIR.mkdir(parents=True, exist_ok=True)
    return _STATIC_DIR


@cache
def _load_index_template() -> str:
    try:
        text = _INDEX_PATH.read_text(encoding="utf-8")
    except FileNotFoundError as exc:  # pragma: no cover — repo ships the stub
        raise DashboardBundleMissing(f"frontend bundle missing at {_INDEX_PATH}; run `bun run web:build`") from exc
    if _CONFIG_SENTINEL not in text:
        raise DashboardBundleMissing(
            f"frontend bundle at {_INDEX_PATH} is missing the {_CONFIG_SENTINEL} sentinel; "
            "rebuild with `bun run web:build`"
        )
    return text


def reset_index_cache() -> None:
    """Drop the cached template. Called by tests that swap the static dir."""
    _load_index_template.cache_clear()


def render_index(replay_token: str | None) -> str:
    """Render the dashboard HTML with the server's replay token baked in.

    The token lands inside a `<script type="application/json">` block that the
    page parses at startup and attaches to every privileged fetch. The user
    never sees or types it; the only credential to manage is the env var on
    the server itself.

View on GitHub (pinned to 9690622007)

Solutions

  1. Run `bun run web:build` again from the repo root to regenerate index.html with the sentinel
  2. Clear any cached/copied build output (dist/, build cache) and rebuild from a clean tree
  3. Do not hand-edit the generated index.html — change the build pipeline that emits the sentinel instead
  4. Pin deploy pipelines to rebuild the web bundle rather than reusing artifact caches
Defensive patterns

Strategy: try-catch

Validate before calling

text = _INDEX_PATH.read_text(encoding="utf-8") if _INDEX_PATH.is_file() else ""
bundle_ok = _CONFIG_SENTINEL in text

Try / catch

try:
    html = render_index()
except DashboardBundleMissing as exc:
    log.warning("stale frontend bundle: %s — rebuilding", exc)
    subprocess.run(["bun", "run", "web:build"], check=True)
    html = render_index()

Prevention

When it happens

Trigger: Calling `render_index` after the index.html at `_INDEX_PATH` was built by an older build script, copied from a different project, hand-edited so the sentinel was removed, or partially overwritten.

Common situations: Stale build artifacts from a previous version surviving a cache, mixing a rebuilt Python package with an old web build, CI restoring an outdated cached `dist/` directory.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/6d7a0ee6e3207a6b. Report an issue: GitHub.