deepseek-ai/deepseek-harness · critical
client-modules: window.__DSH_BOOT__ is missing or not an obj
Error message
client-modules: window.__DSH_BOOT__ is missing or not an object
What it means
The dsh web host injects the composed module graph into the page as window.__DSH_BOOT__ before the client module system starts; parseBootManifest enforces that wire boundary and throws when the value is missing or not an object. The built apps/web Vite shell is not a standalone application — only dsh web performs the injection — so a page served any other way fails here, and the shell shows the loud failure because a page without a valid manifest cannot boot anything.
Source
Thrown at packages/client/modules/src/client/manifest.ts:149
* require path and graph composition normalize here, which is what lets each
* importing package request the subpath its own code imports.
* @param spec - module specifier as a bundle requires it or a declaration spells it.
* @returns the specifier with a trailing `/client` removed.
*/
export function stripClientSuffix(spec: string): string {
return spec.endsWith('/client') ? spec.slice(0, -'/client'.length) : spec
}
/**
* Parse `window.__DSH_BOOT__` into the two consumer views. Wire boundary:
* a missing or malformed graph throws (the shell shows the loud failure —
* a page without a valid manifest cannot boot anything).
* @param wire - the raw `window.__DSH_BOOT__` value.
* @returns the manifest with optional plugin-view fields normalized.
*/
export function parseBootManifest(wire: unknown): BootManifest {
if (typeof wire !== 'object' || wire === null) {
throw new Error('client-modules: window.__DSH_BOOT__ is missing or not an object')
}
const graph = wire as Record<string, unknown>
if (typeof graph.rev !== 'string') {
throw new Error('client-modules: boot manifest rev must be a string')
}
if (!Array.isArray(graph.entries)) {
throw new Error('client-modules: boot manifest entries must be an array')
}
const modules: BootModuleRow[] = []
const plugins: BootPluginRow[] = []
for (const value of graph.entries as unknown[]) {
if (typeof value !== 'object' || value === null) {
throw new Error('client-modules: boot manifest entry is not an object')
}
const row = value as Record<string, unknown>
const where = typeof row.id === 'string' ? `"${row.id}"` : JSON.stringify(row)
if (typeof row.id !== 'string' || typeof row.url !== 'string' || typeof row.rev !== 'string') {
throw new Error(`client-modules: boot manifest entry ${where} must carry string id/url/rev`)View on GitHub (pinned to b150a551b8)
Solutions
- Open the GUI at the URL dsh web prints (loopback or declared authority) — the injection happens only there
- If developing the shell, keep dev rebuild tooling running but still load the page through the running dsh web server
- On a dsh-served URL that still fails, check for a blocked inline boot script (CSP, extensions)
Example fix
// before
const manifest = parseBootManifest((window as any).__DSH_BOOT__)
// after
const wire = (window as { __DSH_BOOT__?: unknown }).__DSH_BOOT__
if (typeof wire !== 'object' || wire === null) {
throw new Error('serve this page via dsh web; window.__DSH_BOOT__ is host-injected')
}
const manifest = parseBootManifest(wire) Defensive patterns
Strategy: type-guard
Validate before calling
const wire = (window as { __DSH_BOOT__?: unknown }).__DSH_BOOT__
if (typeof wire !== 'object' || wire === null) {
showFatalError('open this page through the dsh web URL — the host injects window.__DSH_BOOT__')
} Type guard
function hasBootManifest(w: Window & { __DSH_BOOT__?: unknown }): w is Window & { __DSH_BOOT__: object } {
return typeof w.__DSH_BOOT__ === 'object' && w.__DSH_BOOT__ !== null
} Prevention
- Never deploy or preview dist/ standalone; the shell requires host injection
- Enter only through the dsh web URL
- In e2e, drive the real served page, not a static copy
When it happens
Trigger: Opening the built frontend index.html directly from disk, via vite dev / vite preview, or behind a plain static server; or a host-side inline injection script that failed (CSP or extension blocking) before assigning the global.
Common situations: Frontend development opening the Vite dev server instead of the dsh-served URL; deploying dist/ behind nginx standalone; strict CSP stripping the inline boot script.
Related errors
- client-modules: boot manifest rev must be a string
- ${binName}: profile bundle ${JSON.stringify(packageName)} de
- browser operating-system launcher exited with code ${String(
- client-modules: ${subject} ${field} must be a string array
- client-modules: HTML did not preload ${CLIENT_MODULES_ID}/cl
AI-assisted analysis of deepseek-ai/deepseek-harness@b150a551b8 (2026-08-24).
Data as JSON: /api/errors/e48aae67a000ab08.
Report an issue: GitHub.