[nu-demo] Settings → Environment page errors with 'expected value at line 1 column 1' — WASM hits unrouted /config/env #199

Closed
opened 2026-04-27 14:54:50 +00:00 by mik-tf · 2 comments
Owner

Symptom

In hero_os Settings → Environment tab on herodemo (and any nu-demo deploy), the page renders only the error banner:

Error: expected value at line 1 column 1

No env vars show. The error is a JSON parse failure — the response body is HTML (nginx 404 / auth challenge), not JSON.

Root cause

hero_os_app/src/services/env_service.rs:18-25 builds the RPC URL via:

fn config_env_url() -> String {
    let base = config::osis_url();
    if base.is_empty() {
        "/config/env".to_string()           // ← bug: no service prefix
    } else {
        format!("{}/config/env", base)
    }
}

In same-origin mode (the default for nu-demo behind nginx + hero_router), osis_url() returns "", so the WASM POSTs to https://herodemo.gent01.grid.tf/config/env.

hero_router parses paths as /<service>/<socket_type>/<rest> (e.g. /hero_osis/ui/whatever → routes to hero_osis/ui.sock). /config/env doesn't match this pattern — hero_router rejects it (Socket 'web_env.sock' not found for 'config' → 404), and nginx returns its default error page (HTML).

Verification on herodemo

Hitting hero_router (port 9990) with the correct prefix returns the JSON the page expects:

$ curl -X POST 'http://10.1.2.2:9990/hero_osis/ui/config/env' \
    -H 'Content-Type: application/json' \
    -d '{"jsonrpc":"2.0","id":1,"method":"config.env_list","params":{}}'
{"id":1,"jsonrpc":"2.0","result":[{"category":"Identity","label":"Git Author Name","name":"GIT_NAME",...},...]}

Backend (hero_osis_ui/src/lib.rs:83 .route("/config/env", post(config_env::config_env_rpc))) is fine — it serves on /config/env and the router strips the service+socket prefix correctly. The bug is entirely in the WASM URL builder.

Fix

hero_os_app/src/services/env_service.rs:18:

fn config_env_url() -> String {
    let base = config::osis_url();
    let prefix = "/hero_osis/ui";   // service-prefixed path for hero_router
    if base.is_empty() {
        format!("{}/config/env", prefix)
    } else {
        format!("{}{}/config/env", base, prefix)
    }
}

Or, more in line with how the OSIS SDK already prefixes its calls (see hero_os_app/src/config.rs:37"The OSIS SDK appends /hero_osis_<domain>/rpc itself per call"): introduce a sibling osis_ui_url() helper that returns the legacy hero_osis_ui prefix, and have env_service use it.

Impact / scope

Only the Settings → Environment tab is affected — but it's a visible front-page UX error any new operator hits when trying to set up API keys. (When the API keys tab is broken, the natural next step — running the AI Assistant — also fails until the keys are set via env vars or ~/.profile, compounding confusion.)

Not related to the rc.12 ONNX work (home#173 follow-up). Pre-existing.

Filed during herodemo end-to-end testing 2026-04-27. Surfaced when the user opened Settings → Environment to set API keys.

Signed-off-by: mik-tf

## Symptom In hero_os Settings → Environment tab on herodemo (and any nu-demo deploy), the page renders only the error banner: ``` Error: expected value at line 1 column 1 ``` No env vars show. The error is a JSON parse failure — the response body is HTML (nginx 404 / auth challenge), not JSON. ## Root cause `hero_os_app/src/services/env_service.rs:18-25` builds the RPC URL via: ```rust fn config_env_url() -> String { let base = config::osis_url(); if base.is_empty() { "/config/env".to_string() // ← bug: no service prefix } else { format!("{}/config/env", base) } } ``` In same-origin mode (the default for nu-demo behind nginx + hero_router), `osis_url()` returns `""`, so the WASM POSTs to `https://herodemo.gent01.grid.tf/config/env`. hero_router parses paths as `/<service>/<socket_type>/<rest>` (e.g. `/hero_osis/ui/whatever` → routes to `hero_osis/ui.sock`). `/config/env` doesn't match this pattern — hero_router rejects it (`Socket 'web_env.sock' not found for 'config'` → 404), and nginx returns its default error page (HTML). ## Verification on herodemo Hitting hero_router (port 9990) with the *correct* prefix returns the JSON the page expects: ``` $ curl -X POST 'http://10.1.2.2:9990/hero_osis/ui/config/env' \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","id":1,"method":"config.env_list","params":{}}' {"id":1,"jsonrpc":"2.0","result":[{"category":"Identity","label":"Git Author Name","name":"GIT_NAME",...},...]} ``` Backend (`hero_osis_ui/src/lib.rs:83` `.route("/config/env", post(config_env::config_env_rpc))`) is fine — it serves on `/config/env` and the router strips the service+socket prefix correctly. The bug is entirely in the WASM URL builder. ## Fix `hero_os_app/src/services/env_service.rs:18`: ```rust fn config_env_url() -> String { let base = config::osis_url(); let prefix = "/hero_osis/ui"; // service-prefixed path for hero_router if base.is_empty() { format!("{}/config/env", prefix) } else { format!("{}{}/config/env", base, prefix) } } ``` Or, more in line with how the OSIS SDK already prefixes its calls (see `hero_os_app/src/config.rs:37` — *"The OSIS SDK appends `/hero_osis_<domain>/rpc` itself per call"*): introduce a sibling `osis_ui_url()` helper that returns the legacy hero_osis_ui prefix, and have env_service use it. ## Impact / scope Only the Settings → Environment tab is affected — but it's a visible front-page UX error any new operator hits when trying to set up API keys. (When the API keys tab is broken, the natural next step — running the AI Assistant — also fails until the keys are set via env vars or `~/.profile`, compounding confusion.) Not related to the rc.12 ONNX work (home#173 follow-up). Pre-existing. Filed during herodemo end-to-end testing 2026-04-27. Surfaced when the user opened Settings → Environment to set API keys. Signed-off-by: mik-tf
Author
Owner

Fix landed

hero_os 3dedbd2 on development:

fn config_env_url() -> String {
    let base = config::osis_url();
    let prefix = "/hero_osis/ui";   // was missing
    if base.is_empty() {
        format!("{}/config/env", prefix)
    } else {
        format!("{}{}/config/env", base.trim_end_matches('/'), prefix)
    }
}

Verified on herodemo: /hero_osis/ui/config/env returns the full env list; bare /config/env returned hero_router's 404. WASM rebuild + redeploy needed for the fix to reach the browser, which will happen on the next hero_demo deploy from development.

Closing once that deploy lands.

Signed-off-by: mik-tf

## Fix landed hero_os [`3dedbd2`](https://forge.ourworld.tf/lhumina_code/hero_os/commit/3dedbd2) on development: ```rust fn config_env_url() -> String { let base = config::osis_url(); let prefix = "/hero_osis/ui"; // was missing if base.is_empty() { format!("{}/config/env", prefix) } else { format!("{}{}/config/env", base.trim_end_matches('/'), prefix) } } ``` Verified on herodemo: `/hero_osis/ui/config/env` returns the full env list; bare `/config/env` returned hero_router's 404. WASM rebuild + redeploy needed for the fix to reach the browser, which will happen on the next hero_demo deploy from `development`. Closing once that deploy lands. Signed-off-by: mik-tf
Author
Owner

WASM redeployed to herodemo + regression-prevention layer

All three layers landed:

Pragmatic (live)

  • hero_os WASM rebuilt from development and assets reinstalled to /home/driver/hero/share/hero_os/public/ on herodemo (Apr 27 21:31).
  • hero_router_url symbol confirmed in the deployed hero_os_app_bg.wasm.
  • hero_os service restarted (run_id 88, restarts 0).
  • Server-side /hero_osis/ui/config/env confirmed serving full env JSON via hero_router (10.1.2.2:9990).

Long-term — code

  • hero_os b7b7b90 added config::hero_router_url(service, sock_type, path) and refactored env_service to use it.
  • 4 unit tests guarding the convention live in hero_os_app/src/config.rs and run as part of every cargo test -p hero_os_app --bins:
    • test_hero_router_url_same_origin — the exact regression case
    • test_hero_router_url_health_probe
    • test_hero_router_url_strips_leading_slash_on_path
    • test_hero_router_url_never_drops_service_prefix

Long-term — docs

  • hero_demo 644b417 — runbook §4.5 WASM ↔ service URL routing convention. Front-and-center in DEPLOYMENT_NU_HERO_OS.md so any new contributor reading the deploy doc sees the convention before they write their first WASM RPC call.

Why this wont regress

  1. Compile-time: cargo unit tests fail if the helper produces malformed URLs.
  2. Code-review: ad-hoc format!("/...") builds for service URLs stand out at PR review against the canonical hero_router_url(...) call.
  3. Onboarding: runbook entry makes the convention discoverable without tribal knowledge.

Closing.

Signed-off-by: mik-tf

## WASM redeployed to herodemo + regression-prevention layer All three layers landed: ### Pragmatic (live) * hero_os WASM rebuilt from `development` and assets reinstalled to `/home/driver/hero/share/hero_os/public/` on herodemo (Apr 27 21:31). * `hero_router_url` symbol confirmed in the deployed `hero_os_app_bg.wasm`. * hero_os service restarted (run_id 88, restarts 0). * Server-side `/hero_osis/ui/config/env` confirmed serving full env JSON via hero_router (10.1.2.2:9990). ### Long-term — code * hero_os [`b7b7b90`](https://forge.ourworld.tf/lhumina_code/hero_os/commit/b7b7b90) added `config::hero_router_url(service, sock_type, path)` and refactored `env_service` to use it. * 4 unit tests guarding the convention live in `hero_os_app/src/config.rs` and run as part of every `cargo test -p hero_os_app --bins`: * `test_hero_router_url_same_origin` — the exact regression case * `test_hero_router_url_health_probe` * `test_hero_router_url_strips_leading_slash_on_path` * `test_hero_router_url_never_drops_service_prefix` ### Long-term — docs * hero_demo [`644b417`](https://forge.ourworld.tf/lhumina_code/hero_demo/commit/644b417) — runbook §4.5 *WASM ↔ service URL routing convention*. Front-and-center in `DEPLOYMENT_NU_HERO_OS.md` so any new contributor reading the deploy doc sees the convention before they write their first WASM RPC call. ### Why this wont regress 1. **Compile-time**: cargo unit tests fail if the helper produces malformed URLs. 2. **Code-review**: ad-hoc `format!("/...")` builds for service URLs stand out at PR review against the canonical `hero_router_url(...)` call. 3. **Onboarding**: runbook entry makes the convention discoverable without tribal knowledge. Closing. Signed-off-by: mik-tf
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/home#199
No description provided.