{"record":{"id":"91be601061cabb51","repo":"different-ai/openwork","slug":"app-retired","errorCode":"app_retired","errorMessage":"Restore this app before activating a revision.","messagePattern":"Restore this app before activating a revision\\.","errorType":"http","errorClass":"RemoteMcpAppError","httpStatus":409,"severity":"error","filePath":"ee/apps/den-api/src/remote-mcp-apps.ts","lineNumber":542,"sourceCode":"  })\n  const updatedAt = new Date()\n  await db.update(RemoteMcpAppTable).set({\n    sourceUrl: fetched.sourceUrl,\n    resolvedSourceUrl: fetched.resolvedSourceUrl,\n    updatedAt,\n  }).where(eq(RemoteMcpAppTable.configObjectId, app.configObjectId))\n  const updated = { ...app, sourceUrl: fetched.sourceUrl, resolvedSourceUrl: fetched.resolvedSourceUrl, updatedAt }\n  return serializeApp(updated, \"editor\")\n}\n\nexport async function activateRemoteMcpAppRevision(input: {\n  context: PluginArchActorContext\n  configObjectId: string\n  versionId: string\n}) {\n  const app = await getAppRow(input.context, input.configObjectId, \"editor\")\n  if (app.status === \"retired\") {\n    throw new RemoteMcpAppError(409, \"app_retired\", \"Restore this app before activating a revision.\")\n  }\n  let versionId: DenTypeId<\"configObjectVersion\">\n  try {\n    versionId = normalizeDenTypeId(\"configObjectVersion\", input.versionId)\n  } catch {\n    throw new RemoteMcpAppError(404, \"app_revision_not_found\", \"App revision not found.\")\n  }\n  const versions = await db.select().from(ConfigObjectVersionTable).where(and(\n    eq(ConfigObjectVersionTable.configObjectId, app.configObjectId),\n    eq(ConfigObjectVersionTable.id, versionId),\n    eq(ConfigObjectVersionTable.isDeletedVersion, false),\n  )).limit(1)\n  const version = versions[0]\n  if (!version || !version.rawSourceText) throw new RemoteMcpAppError(404, \"app_revision_not_found\", \"App revision not found.\")\n  const payload = parseVersionPayload(version)\n  if (sha256(version.rawSourceText) !== payload.resource.digest) {\n    throw new RemoteMcpAppError(422, \"cached_app_digest_mismatch\", \"The cached app revision failed its integrity check.\")\n  }","sourceCodeStart":524,"sourceCodeEnd":560,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-api/src/remote-mcp-apps.ts#L524-L560","documentation":"activateRemoteMcpAppRevision refuses to operate on retired apps. If app.status === 'retired', activating a revision is rejected with 409 app_retired; the app must first be restored (setRemoteMcpAppRetired with retired:false). This keeps retirement a blocking state.","triggerScenarios":"Calling activateRemoteMcpAppRevision for an app whose RemoteMcpAppTable.status is 'retired' (previously retired via setRemoteMcpAppRetired({retired:true})).","commonSituations":"Retrying an activation script after the app was retired; CI pipelines activating revisions on apps decommissioned by an admin.","solutions":["Restore the app first: setRemoteMcpAppRetired({ context, configObjectId, retired: false }) with manager role.","Then call activateRemoteMcpAppRevision with the desired versionId.","If the app should stay retired, do not schedule activation work for it."],"exampleFix":"// before\nawait activateRemoteMcpAppRevision({ context, configObjectId, versionId })\n// after\nawait setRemoteMcpAppRetired({ context, configObjectId, retired: false })\nawait activateRemoteMcpAppRevision({ context, configObjectId, versionId })","handlingStrategy":"validation","validationCode":"const app = await getRemoteMcpApp({ context, configObjectId })\nif (app.status === 'retired') throw new Error('Restore the app before activating a revision')","typeGuard":"function isActivatable(app: { status: string }): boolean {\n  return app.status !== 'retired'\n}","tryCatchPattern":"try { await activateRemoteMcpAppRevision({ context, configObjectId, versionId }) } catch (e) {\n  if (e instanceof RemoteMcpAppError && e.code === 'app_retired') {\n    await setRemoteMcpAppRetired({ context, configObjectId, retired: false })\n    // then retry activation\n  }\n}","preventionTips":["Check app.status before scheduling activation work","Skip retired apps in CI/automation pipelines","Restore via setRemoteMcpAppRetired({retired:false}) as an explicit step"],"tags":["state-conflict","http-409","retired"],"backgroundTag":"resource-retired","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}