headroomlabs-ai/headroom · warning
comparator cache_aligner not implemented (Phase 0)
Error message
comparator cache_aligner not implemented (Phase 0)
What it means
HTTP 403 from require_same_origin (loopback_guard.py:245): the request carries 'Origin: null'. Browsers send this from sandboxed iframes, file:// pages, or redirect chains; the guard treats it as an untrustworthy origin and rejects CSRF-style attempts on mutating routes. Non-browser clients send no Origin at all and pass.
Source
Thrown at crates/headroom-parity/src/lib.rs:173
// * `cache_aligner` — needs the volatile-content detector, which lives in
// `headroom-proxy` while this crate depends only on `headroom-core`. Either
// add the dependency or move the detector down into core.
// * `ccr` — the fixtures compare `ccr_retrieve` tool-definition injection
// (`headroom/ccr/tool_injection.py`), which has no Rust port at all.
macro_rules! stub_comparator {
($ty:ident, $name:literal) => {
pub struct $ty;
impl TransformComparator for $ty {
fn name(&self) -> &str {
$name
}
fn run(
&self,
_input: &serde_json::Value,
_config: &serde_json::Value,
) -> Result<serde_json::Value> {
anyhow::bail!(concat!("comparator ", $name, " not implemented (Phase 0)"))
}
}
};
}
stub_comparator!(CacheAlignerComparator, "cache_aligner");
stub_comparator!(CcrComparator, "ccr");
/// Real comparator for the `log_compressor` transform.
///
/// Two wrinkles beyond the usual adapter shape:
///
/// * **bias.** Python's signature is `compress(content, context="", bias=1.0)`
/// and the recorder captured only `content`, so every fixture was produced at
/// the default `bias = 1.0`. Rust takes `bias` positionally — pass 1.0.
/// * **CCR store.** The Python compressor owns its store internally, while Rust
/// mints a `cache_key` only when one is handed to `compress_with_store`.
/// Without a store the CCR branch bails out with `"no store provided"` andView on GitHub (pinned to 322425c43b)
Solutions
- Serve the page over http(s) from a proper origin (same host) instead of file://
- Add allow-same-origin to the embedding iframe's sandbox attribute
- For scripted access, use a non-browser client (curl, SDK) which sends no Origin header
Example fix
<!-- before --> <iframe src="http://127.0.0.1:8080/settings" sandbox="allow-scripts"></iframe> <!-- after --> <iframe src="http://127.0.0.1:8080/settings" sandbox="allow-scripts allow-same-origin"></iframe>
Defensive patterns
Strategy: validation
Validate before calling
// Browser-side: refuse to call mutating endpoints from a null origin
if (location.origin === "null") throw new Error("serve this page over http(s), not file://"); Try / catch
if (resp.status === 403 && detail === "cross-origin request rejected") {
console.error("null origin — serve the page from a real origin");
} Prevention
- Never load control pages from file:// or sandboxed iframes without allow-same-origin
- Use the SDK/CLI for automation — non-browser clients send no Origin
When it happens
Trigger: A dashboard page served from a file:// URL or a sandboxed iframe issues fetch()/XHR with JSON bodies to the local mutating endpoints; a page that redirected through a data: or blob: URL before the request.
Common situations: Opening an HTML report or local tool from disk that talks to the proxy; embedding the dashboard in a sandboxed iframe without allow-same-origin; edge redirects that nullify the origin.
Related errors
- comparator ccr not implemented (Phase 0)
- recommendations TOML parse error: {0}
- fixture {} declares transform={} but lives under {}
- sha256 mismatch for {path.name}: expected {expected}, got {g
- Invalid {TRUSTED_DASHBOARD_CLIENT_CIDRS_ENV} entry: {exc}
AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15).
Data as JSON: /api/errors/165b4dc82f17a675.
Report an issue: GitHub.