{"record":{"id":"3d916d20cad1ef5f","repo":"deepseek-ai/deepseek-harness","slug":"no-serializer-for-reference-source-o-source","errorCode":null,"errorMessage":"no serializer for reference source \"${o.source}\"","messagePattern":"no serializer for reference source \"(.+?)\"","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/client/ui-conversation/src/client/input/facade.ts","lineNumber":466,"sourceCode":"\n  /**\n   * Prompt serialization before the sink: expand each\n   * inline reference range to its owner's model form via the session controller's\n   * codec routing. Owner missing / serialize failure / disposal blocks the\n   * send — notice + draft and chips retained, never a silent downgrade to\n   * the clipboard text. Chip-free drafts skip the async detour.\n   */\n  private sinkSerialized(attempt: SubmitAttempt, draft: string, mode: InputSubmitMode): void {\n    const imageIds = [...this.imageIds]\n    const occurrences = this.core.state.occurrences\n    if (occurrences.length === 0) {\n      this.settleSubmit(attempt, this.deps.defaultSink(draft.trim(), imageIds, mode, attempt.signal), imageIds)\n      return\n    }\n    const inputTriggers = this.deps.inputTriggers?.()\n    const controller = new AbortController()\n    void Promise.all(occurrences.map(async (o) => {\n      if (inputTriggers === undefined) throw new Error(`no serializer for reference source \"${o.source}\"`)\n      return {\n        offset: o.offset,\n        length: o.length,\n        text: await inputTriggers.serializeReference(o.source, o.ref, controller.signal),\n      }\n    })).then(\n      (parts) => {\n        if (this.disposed) return\n        // Splice model forms over their display ranges (offsets are draft-time;\n        // parts arrive offset-sorted since the table is).\n        let out = ''\n        let cursor = 0\n        for (const part of parts) {\n          out += draft.slice(cursor, part.offset) + part.text\n          cursor = part.offset + part.length\n        }\n        out += draft.slice(cursor)\n        this.settleSubmit(attempt, this.deps.defaultSink(out.trim(), imageIds, mode, attempt.signal), imageIds)","sourceCodeStart":448,"sourceCodeEnd":484,"githubUrl":"https://github.com/deepseek-ai/deepseek-harness/blob/b150a551b8d465e31e418e1b2eaf5e79bbb7d28e/packages/client/ui-conversation/src/client/input/facade.ts#L448-L484","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before: facade constructed without the trigger dependency\nconst facade = new InputFacade(core, { defaultSink, /* inputTriggers missing */ })\n// after: wire the trigger source so chip drafts can serialize\nconst facade = new InputFacade(core, { defaultSink, inputTriggers: () => triggerService })","handlingStrategy":"validation","validationCode":"const chips = coreSnapshot.occurrences\nif (chips.length > 0 && inputTriggers?.() === undefined) {\n  blockSubmit('reference chips require the input trigger plugin')\n}","typeGuard":"function canSerializeReferences(deps: FacadeDeps): boolean {\n  return deps.inputTriggers !== undefined && deps.inputTriggers() !== undefined\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["plugin-composition","references","input","dependency-injection"],"backgroundTag":"missing-plugin-dependency","analyzedSha":"b150a551b8d465e31e418e1b2eaf5e79bbb7d28e","analyzedAt":"2026-08-24T18:12:29.105Z","schemaVersion":2},"datasetVersion":"2026-08-24T22:17:12.610Z"}