Budibase/budibase · error

User ID or revision missing

Error message

User ID or revision missing

What it means

In assignExistingUsersToWorkspace, after resolving groups the code needs both user._id and a current _rev to call users.addUserToWorkspace. If either is missing (the user vanished, or the fetched document has no revision) it throws 'User ID or revision missing'. _rev is required for optimistic-concurrency document updates.

Source

Thrown at packages/builder/src/settings/pages/people/users/workspaceInviteUtils.ts:284

          rev = saved?._rev || rev
        }
        if (!user._id) {
          throw new Error("User ID missing")
        }
        if (groupIdsToAdd.length) {
          await Promise.all(
            groupIdsToAdd.map(groupId => groupStore.addUser(groupId, user._id!))
          )
        }
        if (!role) {
          return email
        }
        if (groupIdsToAdd.length || !rev) {
          const loaded = await users.get(user._id)
          rev = loaded?._rev
        }
        if (!user._id || !rev) {
          throw new Error("User ID or revision missing")
        }
        await users.addUserToWorkspace(user._id, role, rev)
        return email
      }
    )
  )

  const assignedUsers = assignmentResults
    .filter(
      (result): result is PromiseFulfilledResult<string> =>
        result.status === "fulfilled"
    )
    .map(result => result.value)
  const addedToWorkspaceEmails = [...groupManagedUsers, ...assignedUsers]

  return {
    usersToInvite,
    addedToWorkspaceEmails,

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Re-fetch the user before assignment to get a fresh _id/_rev and retry.
  2. Verify the user still exists and the current user has permission to read it.
  3. Check the users.get/users.save responses actually include _rev and surface API errors instead of continuing with undefined.

Example fix

// before
if (!user._id || !rev) { throw new Error("User ID or revision missing") }
// after
const fresh = await users.get(user._id)
if (!fresh?._id || !fresh?._rev) { return null } // skip missing/deleted users instead of failing the whole batch
Defensive patterns

Strategy: try-catch

Validate before calling

const withIds = users.filter(u => !!u._id)
const revs = await Promise.all(withIds.map(u => users.get(u._id!).then(l => l?._rev)))
const ready = withIds.filter((u, i) => !!revs[i])

Type guard

const canAssign = (u: Partial<User>, rev?: string): u is User & { _id: string } =>
  typeof u._id === "string" && typeof rev === "string" && rev.length > 0

Try / catch

try {
  await users.addUserToWorkspace(user._id, role, rev)
} catch (e) {
  if (e.message === "User ID or revision missing") {
    console.warn(`Skipping user ${user.email}: deleted or unreadable`)
    return null
  }
  throw e
}

Prevention

When it happens

Trigger: user._id exists but the rev lookup failed: groupIdsToAdd.length > 0 or rev was falsy, so users.get(user._id) was called and returned undefined or a doc without _rev — e.g. the user was deleted concurrently or the get API returned an error object.

Common situations: Concurrent deletion of the user by another admin; the earlier users.save call returned a response without _rev; permission issues preventing the user fetch; stale user objects after another tab saved changes.

Related errors


AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29). Data as JSON: /api/errors/f9df95dce44896e7. Report an issue: GitHub.