Budibase/budibase · error · HTTPError

Resource not found: ${body.resourceId}

Error message

Resource not found: ${body.resourceId}

What it means

Creating a workspace favourite first verifies the target resource exists via verifyResource. If the lookup returns no document (tryGet semantics) or the resource cannot be verified, a 404 HTTPError with the resource ID is raised, and any verification error is re-thrown as a 404 with a descriptive message.

Source

Thrown at packages/server/src/api/controllers/workspaceFavourites.ts:94

    [WorkspaceResource.DATASOURCE]: sdk.datasources.get,
    [WorkspaceResource.QUERY]: sdk.queries.find,
    [WorkspaceResource.VIEW]: sdk.views.get,
    [WorkspaceResource.AGENT]: sdk.ai.agents.getOrThrow,
  }
  const verifyResource: ResourceGetter = check[body.resourceType]

  // Abort if it can't be verified
  if (!verifyResource)
    ctx.throw(
      `Workspace favourite failure. Could not verify resource ${body.resourceId}, ${body.resourceType}`
    )

  // Attempt to find the resource to ensure that it exists
  try {
    const doc = await verifyResource(body.resourceId)
    // tryGet doesnt throw so in the event that a resource doesn't throw, ensure it.
    if (!doc) {
      throw new HTTPError(`Resource not found: ${body.resourceId}`, 404)
    }
  } catch (e: any) {
    ctx.throw(
      404,
      `Workspace favourite failure. Could not verify resource: ${body.resourceId}. ${e.message}`
    )
  }

  const workspaceFavourite = await sdk.workspace.create(newFavourite)
  ctx.status = 201
  ctx.body = {
    ...workspaceFavourite,
  } as AddWorkspaceFavouriteResponse
}

export async function destroy(
  ctx: UserCtx<void, DeleteWorkspaceFavouriteResponse>
) {

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Verify the resource still exists (fetch its doc) and use a valid resourceId.
  2. Check the request is made in the workspace context of the app that owns the resource.
  3. Remove the stale favourite request from the client and refresh the resource list.
  4. If the resource was deleted intentionally, delete the favourite instead of creating it.

Example fix

// before
await api.post('/api/favourites', { resourceId: deletedRowId })
// after
const table = await api.get(`/api/tables/${tableId}`)
if (table) await api.post('/api/favourites', { resourceId: tableId })
Defensive patterns

Strategy: validation

Validate before calling

const doc = await verifyResource(resourceId)
if (!doc) return res.status(404).json({ error: `Resource ${resourceId} does not exist; cannot favourite` })

Type guard

const resourceExists = async (id: string): boolean => Boolean(await verifyResource(id))

Try / catch

try {
  await api.post('/api/favourites', { resourceId })
} catch (e) {
  if (e.status === 404 && /Could not verify resource/.test(e.message)) {
    // refresh resource list, drop the stale favourite
  } else throw e
}

Prevention

When it happens

Trigger: POSTing a favourite whose body.resourceId references a deleted or non-existent table/row/view/query/datasource, or an ID from a different workspace.

Common situations: Stale UI state favouriting an item deleted in another tab; copied resource IDs across apps; resources removed by import/restore operations.

Related errors


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