thedotmack/claude-mem · error
Observation TV UI not found at any expected location
Error message
Observation TV UI not found at any expected location
What it means
The Observation TV route serves a static tv.html cached into memory at module load from <packageRoot>/ui/tv.html or <packageRoot>/plugin/ui/tv.html. If neither file existed when the worker booted, tvHtmlBytes is null, and hitting the TV endpoint throws this error instead of sending a blank or broken page.
Source
Thrown at src/services/worker/http/routes/ViewerRoutes.ts:196
});
});
private handleViewerUI = this.wrapHandler((req: Request, res: Response): void => {
if (!viewerHtmlBytes) {
throw new Error('Viewer UI not found at any expected location');
}
res.setHeader('Content-Type', 'text/html; charset=utf-8');
res.send(viewerHtmlBytes);
});
/**
* Observation TV: the same /stream the viewer consumes, rendered as a
* full-screen fading title card. Static, dependency-free, and served from
* the same origin so the EventSource needs no CORS of its own.
*/
private handleTvUI = this.wrapHandler((req: Request, res: Response): void => {
if (!tvHtmlBytes) {
throw new Error('Observation TV UI not found at any expected location');
}
res.setHeader('Content-Type', 'text/html; charset=utf-8');
res.send(tvHtmlBytes);
});
/**
* The target of the restart link in the observer-outage warning
* (renderObserverHealthWarning). Serves an INERT page: the restart itself is
* the POST /api/admin/restart behind the button, never this GET.
*
* A GET that restarted the worker would fire from any page that could name
* the URL — `<img src="http://localhost:PORT/restart">` on a site the user
* happens to open is enough. Same reason the page does not POST on load: an
* <iframe> would run that script.
*
* Requiring a click is NOT on its own enough, though: an attacker who frames
* this page can still collect a real click through an overlay. So the route
* also refuses to be framed at all — frame-ancestors 'none' for modernView on GitHub (pinned to 8bc631a71a)
Solutions
- Reinstall the package cleanly: rm -rf node_modules && npm install (or npx claude-mem@latest) so ui/tv.html is restored
- Verify the file exists at <packageRoot>/ui/tv.html (or plugin/ui/tv.html) and restart the claude-mem worker
- If installing from source, run the build step that copies ui assets into the package root before starting the worker
Example fix
// before # package missing assets ls node_modules/claude-mem/ui/ # tv.html absent // after rm -rf node_modules package-lock.json && npm install ls node_modules/claude-mem/ui/tv.html && restart claude-mem worker
Defensive patterns
Strategy: try-catch
Validate before calling
import { existsSync } from 'fs';
if (!['ui/tv.html', 'plugin/ui/tv.html'].some(p => existsSync(require('path').join(packageRoot, p)))) {
throw new Error('tv.html missing from package; reinstall claude-mem');
} Try / catch
app.get('/tv', (req, res) => {
if (!tvHtmlBytes) {
res.status(503).send('Observation TV assets missing — reinstall claude-mem.');
return;
}
res.type('html').send(tvHtmlBytes);
}); Prevention
- After installing or upgrading, verify ui/tv.html exists in the package root before starting the worker
- Use clean installs (delete node_modules) to avoid partially extracted packages
- When building from source, run the asset-copy/build step before launching the worker
When it happens
Trigger: Requesting the Observation TV endpoint (handleTvUI route) from a worker whose package install is missing ui/tv.html and plugin/ui/tv.html — typically a broken/partial npm install or a stale published package built before the file was added.
Common situations: Corrupted or interrupted npm install leaving assets behind; running from a dev checkout where ui assets were not built/copied; upgrading claude-mem while an old worker process (without tv.html support) is still serving.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- [uninstall] Worker shutdown attempt failed:
- Worker failed to start before hook, handler will proceed gra
- Transcript path missing or file does not exist: ${transcript
- bun install failed in ${targetDir} ${describeExecError(err)}
- npmPackageRootDirectory: expected package.json at ${root}. B
AI-assisted analysis of thedotmack/claude-mem@8bc631a71a (2026-09-09).
Data as JSON: /api/errors/671067562d0cb236.
Report an issue: GitHub.