{"record":{"id":"56e438dfef433780","repo":"deepseek-ai/deepseek-harness","slug":"conversation-fallback-definition-is-already-regist","errorCode":null,"errorMessage":"conversation fallback Definition is already registered","messagePattern":"conversation fallback Definition is already registered","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/client/runtime/src/client/conversation/event-registry.ts","lineNumber":38,"sourceCode":"    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   */\n  fallbackEntry(): ConversationNodeDefinition | undefined {","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/deepseek-ai/deepseek-harness/blob/b150a551b8d465e31e418e1b2eaf5e79bbb7d28e/packages/client/runtime/src/client/conversation/event-registry.ts#L20-L56","documentation":"The fallback slot is single-occupancy by design: exactly one Definition handles events that no keyed Definition matched. registerFallback() throws when a fallback is already installed — a second registration, even with a different kind, is refused rather than overriding. The disposer frees the slot, and only if the current fallback is still the same object.","triggerScenarios":"A second live call to conversationEvents.registerFallback() while a previous fallback registration is still installed — two packages both claiming the fallback role, or a re-mount whose earlier disposer has not run.","commonSituations":"A new plugin package tries to replace the built-in generic fallback by registering its own; test harnesses install a fallback fixture while the core conversation package (which owns the fallback) is also composed; HMR re-apply racing disposal.","solutions":["Keep exactly one fallback owner (the core conversation package); other features register keyed Definitions with unique kinds instead.","If replacing the fallback is genuinely required, dispose the existing registration (or disable the owning plugin) first, then register — usually via restart.","Remove fallback registration from test fixtures, or ensure the fallback-owning plugin is not composed in that test."],"exampleFix":"// before — two packages both register a fallback\nevents.registerFallback(coreFallback)\nevents.registerFallback(customFallback) // throws: already registered\n\n// after — one fallback owner; others contribute keyed Definitions\nevents.registerFallback(coreFallback)\nevents.register({ kind: 'my.card', ... })","handlingStrategy":"validation","validationCode":"if (events.fallbackEntry() !== undefined) {\n  // the single fallback slot is owned; contribute a keyed Definition instead\n  events.register({ kind: 'my.kind', /* ... */ })\n} else {\n  events.registerFallback(myFallback)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Reserve registerFallback for the one owning package and document the ownership.","Check fallbackEntry() before attempting to install a fallback.","In tests, dispose the runtime between cases so the slot is free."],"tags":["registry","singleton-slot","conversation","fallback"],"backgroundTag":"duplicate-singleton-registration","analyzedSha":"b150a551b8d465e31e418e1b2eaf5e79bbb7d28e","analyzedAt":"2026-08-24T18:12:29.105Z","schemaVersion":2},"datasetVersion":"2026-08-24T22:17:12.610Z"}