deepseek-ai/deepseek-harness · error
client-modules: boot manifest rev must be a string
Error message
client-modules: boot manifest rev must be a string
What it means
The boot graph's rev is the consistency anchor over the whole module graph (content and bundle hashes). parseBootManifest requires it to be a string; a numeric, null, or absent rev means the graph is malformed or was produced by an incompatible host, and the parse refuses it at the wire boundary before any module loads.
Solutions
- Let the host generate the graph: restart dsh web (and pnpm --filter <pkg> bundle after client-plugin changes)
- If you fabricate the wire yourself (fixtures, custom hosts), emit rev as a string
- Use host and frontend from the same checkout/build so the wire shape matches
Example fix
// before (fixture/custom host)
window.__DSH_BOOT__ = { rev: 1724500000000, entries: [...] }
// after
window.__DSH_BOOT__ = { rev: '1724500000000', entries: [...] } Defensive patterns
Strategy: type-guard
Validate before calling
const wire = (window as { __DSH_BOOT__?: unknown }).__DSH_BOOT__
if (typeof wire === 'object' && wire !== null && typeof (wire as { rev?: unknown }).rev !== 'string') {
showFatalError('stale boot graph — rebuild client bundles and restart dsh web')
} Type guard
function hasStringRev(wire: object): wire is object & { rev: string } {
return typeof (wire as { rev?: unknown }).rev === 'string'
} Prevention
- Never hand-write the boot graph; use the host's generator in tests
- Rebuild and restart together when client plugins change
- Treat the wire shape as version-pinned between host and frontend
When it happens
Trigger: window.__DSH_BOOT__ exists as an object but its rev is a number, null, or missing — a custom injection script, a stale host/frontend mix from different builds, or a hand-crafted test fixture.
Common situations: A test or custom host fabricating the graph with rev: Date.now(); mixing an old dsh binary with a newer frontend that changed the wire; manual edits of the injected global while debugging.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- client-modules: window.__DSH_BOOT__ is missing or not an…
- client-modules: must be a string array
- attachment-local: imageCompressionConcurrency must be an…
- BasicCompactionConfig: auto must be a boolean
- BasicCompactionConfig: contextWindow
AI-assisted analysis of deepseek-ai/deepseek-harness@b150a551b8 (2026-08-24).
Data as JSON: /api/errors/7b9597fe4f866d43.
Report an issue: GitHub.
Appendix: source
Thrown at packages/client/modules/src/client/manifest.ts:153
*/
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`)
}
const subject = `boot manifest entry ${where}`
const inject = optionalStringArray(subject, 'inject', row.inject)
const external = optionalStringArray(subject, 'external', row.external)View on GitHub (pinned to b150a551b8)