{"record":{"id":"2981b32b54d9a24c","repo":"Budibase/budibase","slug":"failed-to-refresh-saved-group","errorCode":null,"errorMessage":"Failed to refresh saved group","messagePattern":"Failed to refresh saved group","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/builder/src/stores/portal/groups.ts","lineNumber":62,"sourceCode":"  private async refreshGroup(groupId: string) {\n    const group = await API.getGroup(groupId)\n    this.updateStore(group)\n  }\n\n  async save(group: UserGroup) {\n    const { ...dataToSave } = group\n    delete dataToSave.scimInfo\n    const response = await API.saveGroup(dataToSave)\n    group._id = response._id\n    group._rev = response._rev\n\n    // Setting a default group has side effects on other groups, so refresh all.\n    if (group.isDefault) {\n      const latestGroups = await API.getGroups()\n      this.set(latestGroups)\n      const savedGroup = latestGroups.find(g => g._id === group._id)\n      if (!savedGroup) {\n        throw new Error(\"Failed to refresh saved group\")\n      }\n      return savedGroup\n    }\n\n    this.updateStore(group)\n    return group\n  }\n\n  async delete(group: UserGroup) {\n    await API.deleteGroup(group._id!, group._rev!)\n    this.update(groups => {\n      const index = groups.findIndex(g => g._id === group._id)\n      if (index !== -1) {\n        groups.splice(index, 1)\n      }\n      return groups\n    })\n  }","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/builder/src/stores/portal/groups.ts#L44-L80","documentation":"When saving a group marked as default, setting a default has side effects on other groups, so the store re-fetches all groups and returns the refreshed saved group. If the just-saved group cannot be found in the fresh list, it throws — meaning the server response doesn't include the group, indicating a sync or API inconsistency.","triggerScenarios":"Saving a group with isDefault=true where the subsequent API.getGroups() response does not contain a group with the saved _id — e.g. the group was deleted server-side during the save, the save silently failed server-side, or the _id changed.","commonSituations":"Concurrent deletion of the group by another admin; backend filter excluding the group from the list response; id mismatch between save response and list items; multi-user admin sessions racing on default-group changes.","solutions":["Re-fetch groups and verify the group still exists; retry the save if transient","Check the save API call actually succeeded (inspect its response for errors)","Verify the group's _id matches what the list endpoint returns (no id transformation)","If the group was deleted concurrently, refresh the UI instead of retrying"],"exampleFix":"// before\nconst saved = await groups.save({ ...group, isDefault: true })\n// after\ntry {\n  const saved = await groups.save({ ...group, isDefault: true })\n} catch {\n  await groups.fetch()\n}","handlingStrategy":"try-catch","validationCode":"const list = await API.getGroups()\nif (!list.some(g => g._id === group._id)) {\n  // group is gone or save failed — resync before saving\n}","typeGuard":null,"tryCatchPattern":"try {\n  const saved = await groups.save({ ...group, isDefault: true })\n} catch (e) {\n  if (e.message === \"Failed to refresh saved group\") {\n    await groups.fetch()\n    // surface a refresh/exists message to the user\n  } else throw e\n}","preventionTips":["Verify save responses report success before assuming persistence","Resync group state after any concurrent admin changes","Check id consistency between save and list endpoints","Avoid racing default-group changes across admin sessions"],"tags":["builder","groups","stale-state","sync","portal"],"backgroundTag":"stale-store-state","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}