{"record":{"id":"86a840f4b28b084a","repo":"different-ai/openwork","slug":"workflow-test-capability-mismatch","errorCode":"workflow_test_capability_mismatch","errorMessage":"workflow_test_capability_mismatch:${call.name}","messagePattern":"workflow_test_capability_mismatch:(.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ee/apps/den-api/src/workflows.ts","lineNumber":428,"sourceCode":"  if (consumed[0]) throw new Error(\"workflow_test_receipt_already_used\")\n\n  const built = await input.buildTools()\n  const manifestByPath = new Map(built.manifest.flatMap((entry) => [\n    [entry.scriptPath, entry] as const,\n    [entry.scriptPath.replace(/^tools\\./, \"\"), entry] as const,\n  ]))\n  for (const required of payload.parsed.requiredCapabilities) {\n    const current = manifestByPath.get(required.scriptPath)\n    if (!current || current.capabilityName !== required.capabilityName) {\n      throw new Error(`workflow_capability_unavailable:${required.scriptPath}`)\n    }\n    if (current.readOnly !== true) throw new Error(`workflow_requires_read_only_capabilities:${required.scriptPath}`)\n  }\n  for (const call of parseCodemodeToolCalls(receipt.tool_calls)) {\n    if (!payload.parsed.requiredCapabilities.some((required) => {\n      const normalized = call.name.replace(/^tools\\./, \"\")\n      return required.scriptPath === call.name || required.scriptPath.replace(/^tools\\./, \"\") === normalized\n    })) throw new Error(`workflow_test_capability_mismatch:${call.name}`)\n  }\n\n  const now = new Date()\n  const configObjectVersionId = createDenTypeId(\"configObjectVersion\")\n  await db.transaction(async (tx) => {\n    await tx.insert(ConfigObjectVersionTable).values({\n      id: configObjectVersionId,\n      organizationId: resource.configObject.organizationId,\n      configObjectId: resource.configObject.id,\n      normalizedPayloadJson: payload.value,\n      rawSourceText: input.draft.code,\n      schemaVersion: \"codemode-script-v1\",\n      createdVia: \"cloud\",\n      createdByOrgMembershipId: input.context.organizationContext.currentMember.id,\n      sourceRevisionRef: receipt.id,\n      isDeletedVersion: false,\n      createdAt: now,\n    })","sourceCodeStart":410,"sourceCodeEnd":446,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-api/src/workflows.ts#L410-L446","documentation":"Thrown in createWorkflowVersion when a tool call recorded in the test receipt (receipt.tool_calls) does not correspond to any entry in payload.parsed.requiredCapabilities, after normalizing the 'tools.' prefix. The declared capability list and the calls actually made during the test run must agree exactly.","triggerScenarios":"Registering a workflow where the test run invoked a tool that is not declared in requiredCapabilities — e.g. capabilities were edited after the test ran, or the script changed between test and registration.","commonSituations":"Hand-editing the workflow payload to trim capability declarations; a script that conditionally calls extra tools; stale test receipt from an older script revision.","solutions":["Re-run the workflow test with the current script so requiredCapabilities covers every tool call it makes.","Add the missing tool path to requiredCapabilities (ensuring it is available and read-only).","Remove or guard the extra tool call in the workflow script."],"exampleFix":"// before\nrequiredCapabilities: [{ scriptPath: \"tools.search.web\", capabilityName: \"webSearch\" }]\n// script also calls tools.docs.list\n// after\nrequiredCapabilities: [\n  { scriptPath: \"tools.search.web\", capabilityName: \"webSearch\" },\n  { scriptPath: \"tools.docs.list\", capabilityName: \"docsList\" },\n]","handlingStrategy":"validation","validationCode":"const calls = parseCodemodeToolCalls(receipt.tool_calls).map(c => c.name)\nconst declared = new Set(requiredCapabilities.flatMap(r => [r.scriptPath, r.scriptPath.replace(/^tools\\./, \"\")]))\nconst undeclared = calls.filter(name => !declared.has(name) && !declared.has(name.replace(/^tools\\./, \"\")))\nif (undeclared.length) throw new Error(`undeclared calls: ${undeclared}`)","typeGuard":null,"tryCatchPattern":"try {\n  await createWorkflowVersion(input)\n} catch (e) {\n  if (String(e.message).startsWith(\"workflow_test_capability_mismatch:\")) {\n    const tool = e.message.split(\":\")[1]\n    // declare `tool` in requiredCapabilities or remove the call\n  } else throw e\n}","preventionTips":["Regenerate requiredCapabilities by re-running tests whenever the script changes.","Keep scripts free of conditional tool calls outside the declared set.","Diff receipt.tool_calls against requiredCapabilities before registering."],"tags":["workflow","capability","payload-mismatch","den-api"],"backgroundTag":"capability-declaration-mismatch","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}