deepseek-ai/deepseek-harness · error

conversation fallback Definition is already registered

Error message

conversation fallback Definition is already registered

What it means

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.

Solutions

  1. Keep exactly one fallback owner (the core conversation package); other features register keyed Definitions with unique kinds instead.
  2. If replacing the fallback is genuinely required, dispose the existing registration (or disable the owning plugin) first, then register — usually via restart.
  3. Remove fallback registration from test fixtures, or ensure the fallback-owning plugin is not composed in that test.

Example fix

// before — two packages both register a fallback
events.registerFallback(coreFallback)
events.registerFallback(customFallback) // throws: already registered

// after — one fallback owner; others contribute keyed Definitions
events.registerFallback(coreFallback)
events.register({ kind: 'my.card', ... })
Defensive patterns

Strategy: validation

Validate before calling

if (events.fallbackEntry() !== undefined) {
  // the single fallback slot is owned; contribute a keyed Definition instead
  events.register({ kind: 'my.kind', /* ... */ })
} else {
  events.registerFallback(myFallback)
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of deepseek-ai/deepseek-harness@b150a551b8 (2026-08-24). Data as JSON: /api/errors/56e438dfef433780. Report an issue: GitHub.

Appendix: source

Thrown at packages/client/runtime/src/client/conversation/event-registry.ts:38

    assertDefinitionTarget(definition)
    return this.registerDefinition(
      definition.kind,
      definition,
      `conversation Definition "${definition.kind}" is already registered`,
      `conversationEvents.register(${JSON.stringify(definition.kind)})`,
    )
  }

  /**
   * Register the sole fallback used only when no ordinary Definition matches.
   * @param definition - fallback Definition.
   * @returns idempotent disposer.
   */
  registerFallback(definition: ConversationNodeDefinition): () => void {
    assertDefinitionTarget(definition)
    const target = definition.target
    if (target === undefined) throw new Error('conversation fallback Definition must declare a target')
    if (this.fallback !== undefined) throw new Error('conversation fallback Definition is already registered')
    const owner = this.ctx
    const dispose = owner.effect(() => {
      this.fallback = definition
      this.refresh()
      return () => {
        if (this.fallback !== definition) return
        this.fallback = undefined
        this.refresh()
      }
    }, `conversationEvents.registerFallback(${JSON.stringify(definition.kind)})`)
    return () => { void dispose() }
  }

  /**
   * Return the current unmatched-event fallback.
   * @returns installed fallback, when present.
   */
  fallbackEntry(): ConversationNodeDefinition | undefined {

View on GitHub (pinned to b150a551b8)