Closed bug report

page hero status read 500s on a billboard hero without a screenshot (hero_path null)

Colby Knox · 2mo ago ·closed by Colby Knox

GET /api/pages/:owner/:slug/hero (the freshness/status read behind adom-wiki page hero <ref> with no flags) returns HTTP 500 for a page whose hero is a billboard WITHOUT a screenshot. Reported by Arav Karnik (basic-parts rollout; their 136 pre-existing pages carried exactly this hero shape before they replaced it), reproduced today:

$ adom-wiki page hero adom/adom-bridge-demo --json
{"status":"error","data":{"http_status":500,"response":{"error":"Internal server error"}},"hints":[{"code":"REGISTRY_UNAVAILABLE",...}]}
$ curl -s https://wiki.adom.inc/api/pages/adom/adom-bridge-demo | jq .page.hero_type,.page.hero_path
"billboard"
null
$ curl -s -o /dev/null -w "%{http_code}" https://wiki.adom.inc/hero/adom/adom-bridge-demo
200        # the render itself is fine

Contrast adom/rustdesk-bridge (billboard WITH hero_path docs/hero.png): the same read returns 200 with sha/bytes/url.

Cause (server.js, pageRoute("get", "/hero"), just after the ETag block):

const ext = (page.hero_path.split(".").pop() || "").toLowerCase();

hero_path is legitimately null for a screenshot-less billboard (normalizeHeroSpec: "Screenshot is optional: the composer renders a themed empty window without one, which is what makes born-with-a-hero page creation work"), so .split throws TypeError -> 500. The NO_HERO guard above deliberately lets billboards through without a hero_path, so this line is the only place that still assumes one.

Fix (one line):

const ext = ((page.hero_path || "").split(".").pop() || "").toLowerCase();

(blobSha(null) already returns "" so the ETag path is fine; content_type for a billboard is hard-set to image/svg+xml and does not use ext.) The CLI maps a code-less 500 to REGISTRY_UNAVAILABLE, which is misleading here but correct behavior for a real 500; nothing to change client-side once this ships.

1 Reply

Colby Knox · 2mo ago

Fixed and live on prod (tag ffbea05). The status read called page.hero_path.split() with no guard, but a billboard hero has hero_path = null (the screenshot is optional), so it 500ed. Guarded now with (page.hero_path || ""); ext is unused for a billboard anyway (content_type is forced to image/svg+xml). Verified on prod: repeated GETs of a throwaway screenshot-less billboard hero all return 200. Regression test in test/pages/release-list-hero-status.test.mjs. adom/adom-bridge-demo (the original repro) reads healthy now. Closing.

Log in to reply.