deepseek-ai/deepseek-harness · error
client-modules: ${subject} ${field} must be a string array
Error message
client-modules: ${subject} ${field} must be a string array What it means
optionalStringArray validates the optional array fields (inject, external) read from dsh.client declarations in package.json and from boot-wire rows. An absent field is valid; a present field must be an array containing only strings. Anything else — a bare string, an object, numbers inside the array — fails the scan with the subject (package or wire row) and field named in the message.
Source
Thrown at packages/client/modules/src/client/manifest.ts:122
/** Rows as the module table consumes them. */
modules: BootModuleRow[]
/** Rows as entry composition consumes them. */
plugins: BootPluginRow[]
}
/**
* Validate an optional string-array field read from a `dsh.client` declaration
* or from the boot wire.
* @param subject - diagnostic prefix naming the package or the wire row.
* @param field - field name as it appears in the diagnostic.
* @param value - the raw field value.
* @returns the validated array, or undefined when the field is absent.
* @throws {Error} when the value is present but is not an array of strings.
*/
export function optionalStringArray(subject: string, field: string, value: unknown): string[] | undefined {
if (value === undefined) return undefined
if (!Array.isArray(value) || value.some(item => typeof item !== 'string')) {
throw new Error(`client-modules: ${subject} ${field} must be a string array`)
}
return value as string[]
}
/**
* Normalize a module specifier onto the graph row that owns it: a plugin bundle
* IS its package's client half, so `<id>/client` (the exports subpath external
* bundles emit) and the bare package name resolve to the same exports. Both the
* 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
}
/**View on GitHub (pinned to b150a551b8)
Solutions
- Make the field an array of strings ("inject": ["runtime"]) or remove it — omission is valid
- Use the subject and field named in the message to locate the offending package.json or wire row
- Rebuild the client bundle / boot graph after fixing the manifest
Example fix
// before
"dsh": { "client": { "platform": "web", "inject": "runtime", "external": [7] } }
// after
"dsh": { "client": { "platform": "web", "inject": ["runtime"] } } Defensive patterns
Strategy: type-guard
Validate before calling
function assertOptionalStringArray(field: string, value: unknown): void {
if (value === undefined) return
if (!Array.isArray(value) || value.some(item => typeof item !== 'string')) {
throw new Error(`${field} must be a string array`)
}
}
assertOptionalStringArray('inject', pkg.dsh?.client?.inject)
assertOptionalStringArray('external', pkg.dsh?.client?.external) Type guard
function isStringArray(value: unknown): value is string[] {
return Array.isArray(value) && value.every(item => typeof item === 'string')
} Prevention
- Always write inject/external as arrays, even with one element
- Validate dsh.client manifests with a JSON schema before publishing
- Never hand-edit generated boot graphs
When it happens
Trigger: A package.json declaring dsh.client.inject as a bare string ('runtime') or dsh.client.external containing a non-string entry ([7]); the same malformed shapes arriving on a boot-graph row.
Common situations: Hand-writing a dsh.client manifest and abbreviating a one-element list as a string; generators emitting numbers into external; copy-pasting manifest shapes from a different version's docs.
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: boot manifest rev must be a string
- client-modules: ${pkgName} declares dsh.client but exports n
- attachment-local: imageCompressionConcurrency must be an int
- ${binName}: profile bundle ${JSON.stringify(packageName)} de
- client-connection: trustedHosts entry ${JSON.stringify(entry
AI-assisted analysis of deepseek-ai/deepseek-harness@b150a551b8 (2026-08-24).
Data as JSON: /api/errors/e9819253259ce7db.
Report an issue: GitHub.