{"record":{"id":"92eb284cfa3e754b","repo":"deepseek-ai/deepseek-harness","slug":"provider-mismatch","errorCode":"provider-mismatch","errorMessage":"Context provider ${JSON.stringify(invocation.context)} does not match its strict definition","messagePattern":"Context provider (.+?) does not match its strict definition","errorType":"exception","errorClass":"TypertGatewayError","httpStatus":null,"severity":"error","filePath":"packages/api/gateway/src/index.ts","lineNumber":376,"sourceCode":"\n  private async resolveReceiverContext(\n    descriptor: InvocationDescriptor,\n    args: Readonly<Record<string, unknown>>,\n    endpoint: string,\n  ): Promise<Context> {\n    if (descriptor.invocation.kind === 'direct') return this.ctx\n    const invocation = descriptor.invocation\n    const provider = this.ctx.typert.contexts.getHost(invocation.context)\n    if (provider === undefined) {\n      throw new TypertGatewayError(\n        'context-unavailable',\n        endpoint,\n        `Context provider ${JSON.stringify(invocation.context)} is unavailable`,\n      )\n    }\n    if (provider.wire !== invocation.wire\n      || (invocation.codec.mode === 'strict' && provider.wireTypeSymbol !== invocation.codec.typeSymbol)) {\n      throw new TypertGatewayError(\n        'provider-mismatch',\n        endpoint,\n        `Context provider ${JSON.stringify(invocation.context)} does not match its strict definition`,\n        { field: invocation.wire },\n      )\n    }\n    const identity = decode(invocation.codec, args[invocation.wire], 'input-invalid', endpoint, invocation.wire)\n    let context: Context | undefined\n    try {\n      context = await provider.resolve(identity)\n    } catch (cause) {\n      if (cause instanceof TypertLookupFailure) throw cause\n      throw new TypertGatewayError(\n        'context-failed',\n        endpoint,\n        `Context provider ${JSON.stringify(invocation.context)} failed`,\n        { cause, field: invocation.wire },\n      )","sourceCodeStart":358,"sourceCodeEnd":394,"githubUrl":"https://github.com/deepseek-ai/deepseek-harness/blob/b150a551b8d465e31e418e1b2eaf5e79bbb7d28e/packages/api/gateway/src/index.ts#L358-L394","documentation":"The descriptor records which wire field carries the context identity and, for strict codecs, the wire type symbol. resolveReceiverContext compares both against the live provider's wire and wireTypeSymbol and throws provider-mismatch when they differ: the invocation definition and the runtime provider were generated from different versions of the wire contract, so dispatch would read the wrong args field or validate the identity against the wrong type.","triggerScenarios":"provider.wire !== invocation.wire — for example the descriptor says the identity rides 'sessionId' but the registered provider now declares 'ctxId' — or a strict descriptor whose codec.typeSymbol no longer equals provider.wireTypeSymbol after one side regenerated its type graph.","commonSituations":"Upgrading the provider package without regenerating client descriptors (or the reverse); renaming a context identity wire field in a release; two different versions of the same workspace package resolved inside one dependency tree so an old provider is registered.","solutions":["Regenerate the strict invocation descriptors against the current provider package and redeploy host and client together.","Align package versions across the tree: run pnpm why <provider-package> and pnpm dedupe so a single provider version serves everyone.","If you own the provider and consumers cannot be regenerated yet, restore the previous wire field name and re-release.","Confirm which provider is actually live with typert.contexts.getHost(key) and compare its wire value with the descriptor's invocation.wire."],"exampleFix":"// before — descriptor: invocation.wire = \"sessionId\"; live provider: wire = \"ctxId\"\nawait gateway.invoke(request) // → provider-mismatch (field: sessionId) on every call\n// after — regenerate strict descriptors from the current provider package\n//         so invocation.wire = \"ctxId\" matches, then redeploy both sides together","handlingStrategy":"validation","validationCode":"import type { Context } from '@deepseek-ai/cordis'\nimport type { InvocationDescriptor } from '@deepseek-ai/dsh-typert-protocol'\n\n// Cross-check a descriptor's context invocation against the live provider.\nfunction contextProviderMatches(ctx: Context, descriptor: InvocationDescriptor): boolean {\n  if (descriptor.invocation.kind !== 'context') return true\n  const provider = ctx.typert.contexts.getHost(descriptor.invocation.context)\n  if (provider === undefined || provider.wire !== descriptor.invocation.wire) return false\n  return descriptor.invocation.codec.mode !== 'strict'\n    || provider.wireTypeSymbol === descriptor.invocation.codec.typeSymbol\n}","typeGuard":"import { TypertGatewayError } from '@deepseek-ai/dsh-api-gateway'\n\nfunction isProviderMismatch(error: unknown): error is TypertGatewayError {\n  return error instanceof TypertGatewayError && error.code === 'provider-mismatch'\n}","tryCatchPattern":"try {\n  await gateway.invoke(request)\n} catch (error) {\n  if (error instanceof TypertGatewayError && error.code === 'provider-mismatch') {\n    // deployment skew: quarantine the endpoint until artifacts are regenerated\n    throw new Error(`stale wire contract on ${error.endpoint} (field ${error.field}); regenerate descriptors`)\n  }\n  throw error\n}","preventionTips":["Ship generated strict descriptors and the provider package in one atomic version bump.","Run a boot-time cross-check of every mounted descriptor's wire/typeSymbol against the live registries and fail startup on mismatch.","Gate wire-field renames behind major releases that regenerate every consumer."],"tags":["typert","gateway","provider-mismatch","version-skew","wire-contract","context-provider"],"backgroundTag":"schema-version-mismatch","analyzedSha":"b150a551b8d465e31e418e1b2eaf5e79bbb7d28e","analyzedAt":"2026-08-24T18:12:29.105Z","schemaVersion":2},"datasetVersion":"2026-08-24T22:17:12.610Z"}