{"record":{"id":"f83af29adcb80c8c","repo":"different-ai/openwork","slug":"cached-app-digest-mismatch","errorCode":"cached_app_digest_mismatch","errorMessage":"The cached app revision failed its integrity check.","messagePattern":"The cached app revision failed its integrity check\\.","errorType":"http","errorClass":"RemoteMcpAppError","httpStatus":422,"severity":"error","filePath":"ee/apps/den-api/src/remote-mcp-apps.ts","lineNumber":559,"sourceCode":"  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  }\n  const updatedAt = new Date()\n  await db.update(RemoteMcpAppTable).set({ activeVersionId: versionId, status: \"active\", retiredAt: null, updatedAt })\n    .where(eq(RemoteMcpAppTable.configObjectId, app.configObjectId))\n  return serializeApp({ ...app, activeVersionId: versionId, status: \"active\", retiredAt: null, updatedAt }, \"editor\")\n}\n\nexport async function setRemoteMcpAppRetired(input: {\n  context: PluginArchActorContext\n  configObjectId: string\n  retired: boolean\n}) {\n  const app = await getAppRow(input.context, input.configObjectId, \"manager\")\n  if (!input.retired) {\n    if (!app.activeVersionId) {\n      throw new RemoteMcpAppError(409, \"app_has_no_active_revision\", \"Activate an app revision before restoring it.\")\n    }\n    const updatedAt = new Date()","sourceCodeStart":541,"sourceCodeEnd":577,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-api/src/remote-mcp-apps.ts#L541-L577","documentation":"activateRemoteMcpAppRevision verifies the cached revision's integrity: sha256(version.rawSourceText) must equal payload.resource.digest stored at import/refresh time. On mismatch it throws 422 cached_app_digest_mismatch and refuses activation, protecting against tampered or corrupted cached app source.","triggerScenarios":"Activating a revision where rawSourceText was edited/migrated/corrupted after caching, or the normalized payload's resource.digest was written with a different hashing input (schema/code change between write and verify).","commonSituations":"Manual DB edits to config_object_version rows; storage-layer corruption; a version written by an older den-api build whose digest algorithm or payload shape changed.","solutions":["Run refreshRemoteMcpApp to re-fetch and cache a fresh revision with a correct digest, then activate it.","Delete and re-import the app (importRemoteMcpApp) if the cached revision is unusable.","Confirm the sha256 implementation and payloadForFetchedApp digest computation are consistent across den-api versions.","Check for unauthorized/manual modifications to the config_object_version row."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { await activateRemoteMcpAppRevision({ context, configObjectId, versionId }) } catch (e) {\n  if (e instanceof RemoteMcpAppError && e.code === 'cached_app_digest_mismatch') {\n    // cached source is corrupt/tampered: refreshRemoteMcpApp to re-cache, then activate\n  }\n}","preventionTips":["Never hand-edit config_object_version rows","Re-run refreshRemoteMcpApp after storage migrations that touch rawSourceText","Keep den-api versions consistent so digest computation does not change under cached data"],"tags":["integrity","digest-mismatch","http-422","security"],"backgroundTag":"checksum-mismatch","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}