{"record":{"id":"55a89690a85fe603","repo":"deepseek-ai/deepseek-harness","slug":"conversation-fallback-definition-must-declare-a-ta","errorCode":null,"errorMessage":"conversation fallback Definition must declare a target","messagePattern":"conversation fallback Definition must declare a target","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/client/runtime/src/client/conversation/event-registry.ts","lineNumber":37,"sourceCode":"  register(definition: ConversationNodeDefinition): () => void {\n    assertDefinitionTarget(definition)\n    return this.registerDefinition(\n      definition.kind,\n      definition,\n      `conversation Definition \"${definition.kind}\" is already registered`,\n      `conversationEvents.register(${JSON.stringify(definition.kind)})`,\n    )\n  }\n\n  /**\n   * Register the sole fallback used only when no ordinary Definition matches.\n   * @param definition - fallback Definition.\n   * @returns idempotent disposer.\n   */\n  registerFallback(definition: ConversationNodeDefinition): () => void {\n    assertDefinitionTarget(definition)\n    const target = definition.target\n    if (target === undefined) throw new Error('conversation fallback Definition must declare a target')\n    if (this.fallback !== undefined) throw new Error('conversation fallback Definition is already registered')\n    const owner = this.ctx\n    const dispose = owner.effect(() => {\n      this.fallback = definition\n      this.refresh()\n      return () => {\n        if (this.fallback !== definition) return\n        this.fallback = undefined\n        this.refresh()\n      }\n    }, `conversationEvents.registerFallback(${JSON.stringify(definition.kind)})`)\n    return () => { void dispose() }\n  }\n\n  /**\n   * Return the current unmatched-event fallback.\n   * @returns installed fallback, when present.\n   */","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/deepseek-ai/deepseek-harness/blob/b150a551b8d465e31e418e1b2eaf5e79bbb7d28e/packages/client/runtime/src/client/conversation/event-registry.ts#L19-L55","documentation":"registerFallback() installs the single Definition used when no ordinary Definition matches an event. The fallback is rendered through its own target/buildViewNode pair — there is no match dispatch to route it — so a fallback without a target is rejected. The preceding assertDefinitionTarget already requires target and buildViewNode to be declared together, so reaching this error means the Definition has neither: a match-style shape was passed where a render-target shape is required.","triggerScenarios":"Calling conversationEvents.registerFallback(definition) with a Definition whose target (and therefore buildViewNode) is undefined — reusing an ordinary match/update Definition object as the fallback, or a construction path that conditionally omits the pair.","commonSituations":"Refactoring a plugin and moving its generic renderer to the fallback while keeping the old match-based shape; test fixtures building minimal Definition objects without the target pair; a partial-object spread dropping optional-looking fields.","solutions":["Declare both target and buildViewNode on the fallback Definition — they must appear together.","If the object was meant for match dispatch (match/update), register it with register() instead of registerFallback().","Inspect the Definition construction site: a missing pair is usually a spread or partial-object bug, not an intentional shape."],"exampleFix":"// before — match-style Definition passed as the fallback\nevents.registerFallback({ kind: 'generic', match, update }) // no target/buildViewNode → throws\n\n// after — the fallback declares its render target pair\nevents.registerFallback({\n  kind: 'generic',\n  target: 'generic',\n  buildViewNode: m => ({ key: m.id, kind: 'generic', id: m.id, target: 'generic', data: m }),\n})","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"import type { ConversationNodeDefinition } from '../contract/conversation.ts'\ntype FallbackDefinition = ConversationNodeDefinition & {\n  target: string\n  buildViewNode: NonNullable<ConversationNodeDefinition['buildViewNode']>\n}\nconst isFallbackDefinition = (d: ConversationNodeDefinition): d is FallbackDefinition =>\n  d.target !== undefined && d.buildViewNode !== undefined","tryCatchPattern":null,"preventionTips":["Construct fallback Definitions from one dedicated factory that always sets the target pair.","Carry the narrowed FallbackDefinition type to the registerFallback call site so the compiler rejects match-style shapes.","Type-check fixtures against the same guard."],"tags":["validation","conversation","fallback","definition"],"backgroundTag":"missing-required-field","analyzedSha":"b150a551b8d465e31e418e1b2eaf5e79bbb7d28e","analyzedAt":"2026-08-24T18:12:29.105Z","schemaVersion":2},"datasetVersion":"2026-08-24T22:17:12.610Z"}