deepseek-ai/deepseek-harness · error
conversation fallback Definition must declare a target
Error message
conversation fallback Definition must declare a target
What it means
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.
Source
Thrown at packages/client/runtime/src/client/conversation/event-registry.ts:37
register(definition: ConversationNodeDefinition): () => void {
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.
*/View on GitHub (pinned to b150a551b8)
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.
Example fix
// before — match-style Definition passed as the fallback
events.registerFallback({ kind: 'generic', match, update }) // no target/buildViewNode → throws
// after — the fallback declares its render target pair
events.registerFallback({
kind: 'generic',
target: 'generic',
buildViewNode: m => ({ key: m.id, kind: 'generic', id: m.id, target: 'generic', data: m }),
}) Defensive patterns
Strategy: type-guard
Type guard
import type { ConversationNodeDefinition } from '../contract/conversation.ts'
type FallbackDefinition = ConversationNodeDefinition & {
target: string
buildViewNode: NonNullable<ConversationNodeDefinition['buildViewNode']>
}
const isFallbackDefinition = (d: ConversationNodeDefinition): d is FallbackDefinition =>
d.target !== undefined && d.buildViewNode !== undefined Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.
Related errors
- conversation fallback Definition is already registered
- attachment-local: imageCompressionConcurrency must be an int
- client-connection: trustedHosts entry ${JSON.stringify(entry
- client-connection maxRequestBodyBytes (${String(maxRequestBo
- client-modules: ${subject} ${field} must be a string array
AI-assisted analysis of deepseek-ai/deepseek-harness@b150a551b8 (2026-08-24).
Data as JSON: /api/errors/55a89690a85fe603.
Report an issue: GitHub.