deepseek-ai/deepseek-harness · error
no serializer for reference source "${o.source}"
Error message
no serializer for reference source "${o.source}" What it means
Before sinking a submit, the input facade expands every inline reference occurrence (mention chips) into its model form via the inputTriggers service's serializeReference. inputTriggers is an optional injected dependency (deps.inputTriggers?.()); if it is not wired while the draft contains occurrences, no serializer exists for the occurrence's source and the submit is aborted with this error. The code deliberately refuses a silent downgrade to the clipboard text: the notice shows and the draft plus chips are retained.
Source
Thrown at packages/client/ui-conversation/src/client/input/facade.ts:466
/**
* Prompt serialization before the sink: expand each
* inline reference range to its owner's model form via the session controller's
* codec routing. Owner missing / serialize failure / disposal blocks the
* send — notice + draft and chips retained, never a silent downgrade to
* the clipboard text. Chip-free drafts skip the async detour.
*/
private sinkSerialized(attempt: SubmitAttempt, draft: string, mode: InputSubmitMode): void {
const imageIds = [...this.imageIds]
const occurrences = this.core.state.occurrences
if (occurrences.length === 0) {
this.settleSubmit(attempt, this.deps.defaultSink(draft.trim(), imageIds, mode, attempt.signal), imageIds)
return
}
const inputTriggers = this.deps.inputTriggers?.()
const controller = new AbortController()
void Promise.all(occurrences.map(async (o) => {
if (inputTriggers === undefined) throw new Error(`no serializer for reference source "${o.source}"`)
return {
offset: o.offset,
length: o.length,
text: await inputTriggers.serializeReference(o.source, o.ref, controller.signal),
}
})).then(
(parts) => {
if (this.disposed) return
// Splice model forms over their display ranges (offsets are draft-time;
// parts arrive offset-sorted since the table is).
let out = ''
let cursor = 0
for (const part of parts) {
out += draft.slice(cursor, part.offset) + part.text
cursor = part.offset + part.length
}
out += draft.slice(cursor)
this.settleSubmit(attempt, this.deps.defaultSink(out.trim(), imageIds, mode, attempt.signal), imageIds)View on GitHub (pinned to b150a551b8)
Solutions
- Register and provide the inputTriggers service — load the plugin that owns reference serialization — in the composition
- Clear the reference chips from the draft; a chip-free draft submits through the default sink without the serializer
- In tests, inject a stub inputTriggers whose serializeReference resolves
Example fix
// before: facade constructed without the trigger dependency
const facade = new InputFacade(core, { defaultSink, /* inputTriggers missing */ })
// after: wire the trigger source so chip drafts can serialize
const facade = new InputFacade(core, { defaultSink, inputTriggers: () => triggerService }) Defensive patterns
Strategy: validation
Validate before calling
const chips = coreSnapshot.occurrences
if (chips.length > 0 && inputTriggers?.() === undefined) {
blockSubmit('reference chips require the input trigger plugin')
} Type guard
function canSerializeReferences(deps: FacadeDeps): boolean {
return deps.inputTriggers !== undefined && deps.inputTriggers() !== undefined
} Prevention
- Declare the trigger provider as a required input of any composition that allows chips
- Fail at composition time when references are possible but no serializer exists
- In tests, always inject a stub inputTriggers with serializeReference
When it happens
Trigger: A draft carrying reference chips (occurrences.length > 0) is submitted while deps.inputTriggers?.() returns undefined — the trigger provider plugin is not loaded or registered, failed activation, or a test constructed the facade without the dependency. Chip-free drafts skip the async detour entirely and never hit this.
Common situations: A custom embedder composing ui-conversation without the input-trigger provider plugin; a plugin load failure or composition regression after an upgrade; a persisted draft containing chips restored on a mount where the trigger plugin is absent.
Related errors
- lookup-unavailable
- permission settings has no defaultPreset value
- web boot: ${String(failures.length)} entr${failures.length =
AI-assisted analysis of deepseek-ai/deepseek-harness@b150a551b8 (2026-08-24).
Data as JSON: /api/errors/3d916d20cad1ef5f.
Report an issue: GitHub.