{"record":{"id":"e70e496bf258dab7","repo":"Budibase/budibase","slug":"oauth2-config-with-id-config-id-not-found","errorCode":null,"errorMessage":"OAuth2 config with id '${config._id}' not found.","messagePattern":"OAuth2 config with id '(.+?)' not found\\.","errorType":"http","errorClass":"HTTPError","httpStatus":404,"severity":"error","filePath":"packages/server/src/sdk/workspace/oauth2/crud.ts","lineNumber":74,"sourceCode":"    _rev: response.rev!,\n    ...config,\n  }\n}\n\nexport async function get(id: string): Promise<OAuth2Config | undefined> {\n  const db = context.getWorkspaceDB()\n  return await db.tryGet(id)\n}\n\nexport async function update(\n  config: CreatedOAuthConfig\n): Promise<CreatedOAuthConfig> {\n  const db = context.getWorkspaceDB()\n  await guardName(config.name, config._id)\n\n  const existing = await get(config._id)\n  if (!existing) {\n    throw new HTTPError(`OAuth2 config with id '${config._id}' not found.`, 404)\n  }\n\n  const toUpdate = {\n    ...config,\n    clientSecret:\n      config.clientSecret === PASSWORD_REPLACEMENT\n        ? existing.clientSecret\n        : config.clientSecret,\n  }\n\n  const result = await db.put(toUpdate)\n\n  await cleanCache(config._id)\n\n  return { ...toUpdate, _rev: result.rev }\n}\n\nexport async function remove(configId: string, _rev: string): Promise<void> {","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/sdk/workspace/oauth2/crud.ts#L56-L92","documentation":"When updating an OAuth2 configuration via sdk.workspace.oauth2.update, the SDK first re-reads the existing config document from the workspace DB with get(config._id). If no document exists with that id, it throws this 404 HTTPError. It exists so a stale or fabricated config object cannot be silently upserted over a deleted config.","triggerScenarios":"Calling update(config) with a CreatedOAuthConfig whose _id does not exist in the current workspace DB — e.g. the config was deleted by another user/process, the id is wrong or belongs to another workspace, or the caller passes a fabricated/hardcoded id.","commonSituations":"Stale UI after two admins delete/edit the same config concurrently; copying config ids between dev/prod workspaces; passing an id without the oauth2 config doc-id prefix; restoring a workspace from backup without the config docs.","solutions":["Re-fetch the config list (sdk fetch()) and confirm the _id exists before updating","Call create() instead of update() when the config does not exist yet","Verify you are running in the correct workspace context (getWorkspaceDB)","Refresh the client-side state so you are not editing a deleted config"],"exampleFix":"// before\nawait sdk.workspace.oauth2.update({ ...staleConfig, name: 'renamed' })\n// after\nconst existing = await sdk.workspace.oauth2.get(staleConfig._id)\nif (!existing) {\n  const created = await sdk.workspace.oauth2.create({ name: 'renamed', ...rest })\n} else {\n  await sdk.workspace.oauth2.update({ ...staleConfig, name: 'renamed' })\n}","handlingStrategy":"validation","validationCode":"const configs = await sdk.workspace.oauth2.fetch()\nif (!configs.some(c => c._id === config._id)) {\n  throw new Error(`OAuth2 config ${config._id} no longer exists; recreate before updating`)\n}","typeGuard":"function isExistingConfig(\n  c: CreatedOAuthConfig | undefined\n): c is CreatedOAuthConfig {\n  return !!c && typeof c._id === \"string\" && typeof c._rev === \"string\"\n}","tryCatchPattern":"try {\n  await sdk.workspace.oauth2.update(config)\n} catch (e) {\n  if (e instanceof HTTPError && e.status === 404) {\n    // recreate or surface 'config was deleted'\n  } else throw e\n}","preventionTips":["Always re-fetch configs before edit instead of caching _id/_rev across sessions","Check e.status === 404 to distinguish deleted vs other failures","Ensure ids come from the same workspace you operate in"],"tags":["oauth2","not-found","crud"],"backgroundTag":"resource-not-found","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}