deepseek-ai/deepseek-harness · error
sessions.provide: duplicate hook "${name}"
Error message
sessions.provide: duplicate hook "${name}" What it means
Thrown at registration time while building the static no-session kit (SessionProvideChannel.materializeMaybeInfo): two providers on the roster declare the same hook name, or one descriptor lists the name twice. The check runs inside applyRosterChange before any live bundle rebuilds, so a failing sessions.provide() call rolls the provider off the roster and rethrows — the channel never stays on a roster it cannot materialize. The runtime's own built-in first provider already declares the hook 'session' (useSession rides it), so any plugin declaring 'session' hits this immediately.
Source
Thrown at packages/client/runtime/src/client/sessions/provide.ts:180
// session's projection store (open key space — never a static roster member).
projections: { faceOf: key => binding.session.projections.faceOf(key) },
}
}
/** Rebuild the static projection and the owner's live bundles, then republish the current one. */
private applyRosterChange(): void {
this.maybeInfoCache = this.materializeMaybeInfo()
this.host.rebuildBundles()
this.publishCurrent()
}
/** Build the static no-session kit and reject duplicate declared names. */
private materializeMaybeInfo(): SessionMaybeProvideInfo {
const hooks: Record<string, undefined> = {}
const props: Record<string, undefined> = {}
for (const descriptor of this.providers) {
for (const name of descriptor.hooks ?? []) {
if (Object.hasOwn(hooks, name)) throw new Error(`sessions.provide: duplicate hook "${name}"`)
hooks[name] = undefined
}
for (const name of descriptor.props ?? []) {
if (Object.hasOwn(props, name)) throw new Error(`sessions.provide: duplicate prop "${name}"`)
props[name] = undefined
}
}
return { sessionId: undefined, hooks, props } // no projections face: every key reads absent without a session
}
}
View on GitHub (pinned to b150a551b8)
Solutions
- Rename the colliding hook so each name has exactly one owner, namespaced like 'review.sessionState'
- Remove the duplicate declaration from one descriptor's hooks array
- Never declare 'session' — the built-in provider owns it and useSession depends on it
Example fix
// before — collides with the runtime's reserved 'session' hook
sessions.provide({ hooks: ['session'], resolve: (b) => ({ hooks: { session: b.session } }) })
// after — unique, namespaced hook name
sessions.provide({
hooks: ['review.sessionState'],
resolve: (b) => ({ hooks: { 'review.sessionState': reviewStateOf(b) } }),
}) Defensive patterns
Strategy: validation
Validate before calling
// hooks variant of the roster uniqueness check
function assertUniqueHooks(descriptors: SessionProvideDescriptor[]): void {
const seen = new Set<string>()
for (const descriptor of descriptors) {
for (const name of descriptor.hooks ?? []) {
if (seen.has(name)) throw new Error(`duplicate hook ${name}`)
seen.add(name)
}
}
} Try / catch
try {
const disposer = sessions.provide(descriptor)
} catch (error) {
// the channel rolled the provider off the roster and rethrew; rename the hook and retry
} Prevention
- Treat 'session' as reserved — the runtime's built-in provider owns it
- Namespace hook names by plugin, e.g. 'review.sessionState'
- Run the roster uniqueness assertion in plugin tests before registration
When it happens
Trigger: Calling sessions.provide with a descriptor whose hooks include a name another live provider already declared — including the reserved 'session' — or the same name twice within one descriptor. Also reachable from the channel-constructor path when a host assembles an invalid initial roster, and re-validated when a disposer shrinks the roster.
Common situations: Copy-pasting a provider without renaming its hooks; upgrading a plugin that starts declaring a hook another plugin already owns; test fixtures assembling provider rosters directly instead of through provide().
Related errors
- sessions.provide: duplicate prop "${name}"
- lookup-unavailable
- sessions.provide: missing prop "${name}"
AI-assisted analysis of deepseek-ai/deepseek-harness@b150a551b8 (2026-08-24).
Data as JSON: /api/errors/9f908a25792c1297.
Report an issue: GitHub.