{"record":{"id":"7aea38f2a317ec2d","repo":"different-ai/openwork","slug":"workflow-capability-unavailable","errorCode":"workflow_capability_unavailable","errorMessage":"workflow_capability_unavailable:${required.scriptPath}","messagePattern":"workflow_capability_unavailable:(.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ee/apps/den-api/src/workflows.ts","lineNumber":420,"sourceCode":"    throw new Error(\"workflow_matching_test_receipt_required\")\n  }\n\n  const consumed = await db.select({ id: ConfigObjectVersionTable.id }).from(ConfigObjectVersionTable).where(and(\n    eq(ConfigObjectVersionTable.organizationId, resource.configObject.organizationId),\n    eq(ConfigObjectVersionTable.configObjectId, resource.configObject.id),\n    eq(ConfigObjectVersionTable.sourceRevisionRef, receipt.id),\n  )).limit(1)\n  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,","sourceCodeStart":402,"sourceCodeEnd":438,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-api/src/workflows.ts#L402-L438","documentation":"Thrown in createWorkflowVersion when a capability declared in payload.requiredCapabilities cannot be matched to an entry in the built tools manifest. The manifest is indexed by scriptPath (both 'tools.'-prefixed and stripped forms); if the path is missing or its capabilityName differs from what the workflow payload requires, the version is rejected. This guards against registering workflows that reference capabilities that no longer exist or were renamed.","triggerScenarios":"Registering a workflow version whose parsed.requiredCapabilities references a scriptPath absent from input.buildTools() output, or whose capabilityName was changed/renamed since the test run was recorded.","commonSituations":"A tool/script was renamed or deleted after the workflow test ran; the payload's requiredCapabilities were hand-edited; deploying against an environment where a plugin capability is not installed.","solutions":["Re-run the workflow test in the current environment so requiredCapabilities are regenerated against the current manifest.","Update requiredCapabilities (or the workflow payload) to match the current scriptPath and capabilityName.","Restore/reinstall the missing plugin capability or script referenced by the workflow."],"exampleFix":"// before\nrequiredCapabilities: [{ scriptPath: \"tools.search.web\", capabilityName: \"web-search-v1\" }]\n// after (match the current manifest entry)\nrequiredCapabilities: [{ scriptPath: \"tools.search.webSearch\", capabilityName: \"webSearch\" }]","handlingStrategy":"validation","validationCode":"const built = await buildTools()\nconst paths = new Set(built.manifest.flatMap(m => [m.scriptPath, m.scriptPath.replace(/^tools\\./, \"\")]))\nconst missing = requiredCapabilities.filter(r => !paths.has(r.scriptPath))\nif (missing.length) throw new Error(`unavailable: ${missing.map(m => m.scriptPath)}`)","typeGuard":"const isAvailable = (m: {scriptPath: string; capabilityName: string}[], r: {scriptPath: string; capabilityName: string}) =>\n  m.some(e => (e.scriptPath === r.scriptPath || e.scriptPath.replace(/^tools\\./, \"\") === r.scriptPath.replace(/^tools\\./, \"\")) && e.capabilityName === r.capabilityName)","tryCatchPattern":"try {\n  await createWorkflowVersion(input)\n} catch (e) {\n  if (String(e.message).startsWith(\"workflow_capability_unavailable:\")) {\n    const path = e.message.split(\":\")[1]\n    // reinstall/rename capability at `path` or refresh requiredCapabilities\n  } else throw e\n}","preventionTips":["Re-run the workflow test after any plugin/script rename or removal.","Never hand-edit requiredCapabilities; generate them from test runs.","Assert capability availability in CI before registering workflow versions."],"tags":["workflow","capability","manifest-mismatch","den-api"],"backgroundTag":"capability-not-found","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}