deepseek-ai/deepseek-harness · error · TypertGatewayError

context-unavailable

context-unavailable

Error message

Context provider ${JSON.stringify(marker.invocation.context)} is unavailable

What it means

Thrown while the Gateway derives a weak (SRC-marker) invocation descriptor: the Remote method marker declares a context-scoped receiver (invocation.kind === 'context'), but typert.contexts.getHost() finds no Host Context provider registered under the marker's context key. Without that provider the Gateway cannot map a wire identity to the scoped Cordis Context the method must run in, so it refuses to build the descriptor before any request validation happens.

Source

Thrown at packages/api/gateway/src/index.ts:324

          codec: { mode: 'src-json' },
        }
      if (wires.has(parameter.wire)) {
        throw new TypertGatewayError(
          'signature-invalid',
          endpoint,
          `multiple parameters use wire field ${JSON.stringify(parameter.wire)}`,
          { field: parameter.wire },
        )
      }
      wires.add(parameter.wire)
      parameters.push(parameter)
    }

    let receiver: InvocationDescriptor['invocation'] = { kind: 'direct' }
    if (marker.invocation.kind === 'context') {
      const provider = this.ctx.typert.contexts.getHost(marker.invocation.context)
      if (provider === undefined) {
        throw new TypertGatewayError(
          'context-unavailable',
          endpoint,
          `Context provider ${JSON.stringify(marker.invocation.context)} is unavailable`,
        )
      }
      if (wires.has(provider.wire)) {
        throw new TypertGatewayError(
          'signature-invalid',
          endpoint,
          `Context identity conflicts with wire field ${JSON.stringify(provider.wire)}`,
          { field: provider.wire },
        )
      }
      receiver = {
        kind: 'context',
        context: marker.invocation.context,
        wire: provider.wire,
        codec: { mode: 'src-json' },

View on GitHub (pinned to b150a551b8)

Solutions

  1. Add the plugin that registers the Host Context provider for the key shown in the message (the JSON.stringify'd value is the exact registry key) to the same composition as the Remote exporter.
  2. Verify the registerHost key string matches the merge-declared TypertContextMap key exactly, including spelling and case.
  3. If the provider was disposed by HMR or a plugin reload, restart the host process so registration is fresh.
  4. If the method should not be context-scoped, remove the context invocation from its Remote marker so the receiver resolves directly.

Example fix

# before — remote exporter mounted, context provider missing
plugins:
  - dsh-session-remotes
# after — plugin owning the 'session' Host Context loads too
plugins:
  - dsh-session        # calls typert.contexts.registerHost('session', provider)
  - dsh-session-remotes
Defensive patterns

Strategy: validation

Validate before calling

import type { Context } from '@deepseek-ai/cordis'

// Fail at composition/boot time instead of at first RPC.
function assertHostContext(ctx: Context, key: string): void {
  if (ctx.typert.contexts.getHost(key) === undefined) {
    throw new Error(`Host Context provider "${key}" is not registered; load its owning plugin before mounting remotes`)
  }
}

Type guard

import { TypertGatewayError } from '@deepseek-ai/dsh-api-gateway'

function isContextUnavailable(error: unknown): error is TypertGatewayError {
  return error instanceof TypertGatewayError && error.code === 'context-unavailable'
}

Try / catch

try {
  await gateway.invoke({ namespace: 'session:chat', method: 'send', args: { sessionId, text } })
} catch (error) {
  if (error instanceof TypertGatewayError && error.code === 'context-unavailable') {
    // composition defect, not request state: surface as setup error, never retry
    throw new Error(`host misconfigured: ${error.message}`)
  }
  throw error
}

Prevention

When it happens

Trigger: Any dispatch (direct typertGateway.invoke or a Connection RPC) to an endpoint whose Service marker declares a context-scoped method while the plugin that calls typert.contexts.registerHost(<key>, provider) for that context kind is not active — e.g. calling a 'session:<ns>/<method>' scoped remote on a host that never loaded the plugin providing the 'session' Host Context.

Common situations: cordis.yml loads the Remote-exporting plugin but omits the plugin owning the scoped Context; the provider plugin was disposed or reloaded via HMR; the merge-declared TypertContextMap key was renamed on one side (marker or registerHost) so the strings no longer match.

Related errors


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