{"record":{"id":"3362b24f51261997","repo":"Budibase/budibase","slug":"app-not-found-with-id-workspaceapp-id","errorCode":null,"errorMessage":"App not found with id \"${workspaceApp._id}\"","messagePattern":"App not found with id \"(.+?)\"","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/builder/src/stores/builder/workspaceApps.ts","lineNumber":153,"sourceCode":"      disabled: workspaceApp.disabled,\n      ...(Object.hasOwn(workspaceApp, \"projectIds\")\n        ? { projectIds: workspaceApp.projectIds }\n        : {}),\n      ...(Object.hasOwn(workspaceApp, \"theme\")\n        ? { theme: workspaceApp.theme }\n        : {}),\n      ...(Object.hasOwn(workspaceApp, \"customTheme\")\n        ? { customTheme: workspaceApp.customTheme }\n        : {}),\n    }\n\n    const updatedWorkspaceApp = await API.workspaceApp.update(safeWorkspaceApp)\n    this.store.update(state => {\n      const index = state.workspaceApps.findIndex(\n        app => app._id === workspaceApp._id\n      )\n      if (index === -1) {\n        throw new Error(`App not found with id \"${workspaceApp._id}\"`)\n      }\n\n      state.workspaceApps[index] = {\n        ...updatedWorkspaceApp.workspaceApp,\n      }\n      return state\n    })\n  }\n\n  async delete(id: string, rev: string) {\n    await API.workspaceApp.delete(id, rev)\n\n    this.store.update(state => {\n      return {\n        ...state,\n        workspaceApps: state.workspaceApps.filter(app => app._id !== id),\n      }\n    })","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/builder/src/stores/builder/workspaceApps.ts#L135-L171","documentation":"After updating a workspace app via the API, edit() syncs the local store by finding the app's index by _id. If the updated app no longer exists in the local store list (index -1), it throws, indicating store state is out of sync with the server.","triggerScenarios":"toggleDisabled(workspaceAppId) calls edit() for an app id that was removed from the store (deleted elsewhere/concurrently) or never present locally, even though the API update succeeded.","commonSituations":"Two browser tabs — one deletes the app while the other toggles it; stale store after external deletion; passing a wrong/nonexistent _id to toggleDisabled; store not refreshed after another user's changes.","solutions":["Refresh the workspace apps list before toggling if it may be stale","Check the app wasn't deleted in another tab/session; re-fetch via API.workspaceApp.fetch","Verify the workspaceAppId passed to toggleDisabled is correct","If hit inside edit() after a successful API update, reload the store state and retry"],"exampleFix":"// before\nawait workspaceApps.toggleDisabled(appId, true)\n// after\nconst exists = get(workspaceApps).workspaceApps.some(a => a._id === appId)\nif (!exists) await workspaceApps.fetch()\nawait workspaceApps.toggleDisabled(appId, true)","handlingStrategy":"retry","validationCode":"const existsLocally = get(workspaceApps).workspaceApps.some(a => a._id === appId)\nif (!existsLocally) await workspaceApps.fetch()","typeGuard":null,"tryCatchPattern":"try {\n  await workspaceApps.toggleDisabled(appId, state)\n} catch (e) {\n  if (e.message.startsWith(\"App not found with id\")) {\n    await workspaceApps.fetch()\n    // re-check and inform user the app no longer exists\n  } else throw e\n}","preventionTips":["Refresh the workspace apps list after external changes","Avoid holding app ids across long-lived sessions without refresh","Verify ids passed to toggleDisabled come from current store state","Handle multi-tab deletion scenarios in the UI"],"tags":["builder","workspace-apps","stale-state","sync"],"backgroundTag":"stale-store-state","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}