Budibase/budibase · error · HTTPError
View ${view.id} not found in table ${tableId}
Error message
View ${view.id} not found in table ${tableId} What it means
sdk.views.update looks up the existing view in the table by view.id and requires it to exist (with a name). If the id doesn't correspond to any view on the table, an HTTPError 404 'View ${view.id} not found in table ${tableId}' is thrown rather than silently creating.
Source
Thrown at packages/server/src/sdk/workspace/views/internal.ts:76
table.views[view.name] = view
await db.put(table)
return view
}
export async function update(
tableId: string,
view: Readonly<ViewV2>
): Promise<{ view: ViewV2; existingView: ViewV2 }> {
const db = context.getWorkspaceDB()
const table = await sdk.tables.getTable(tableId)
table.views ??= {}
const existingView = Object.values(table.views).find(
v => isV2(v) && v.id === view.id
)
if (!existingView || !existingView.name) {
throw new HTTPError(`View ${view.id} not found in table ${tableId}`, 404)
}
if (isV2(existingView) && existingView.type !== view.type) {
throw new HTTPError(`Cannot update view type after creation`, 400)
}
view = ensureQuerySet(view)
view = ensureQueryUISet(view)
delete table.views[existingView.name]
table.views[view.name] = view
await db.put(table)
return { view, existingView } as { view: ViewV2; existingView: ViewV2 }
}
export async function remove(viewId: string): Promise<ViewV2> {
const db = context.getWorkspaceDB()
View on GitHub (pinned to a81a902e9a)
Solutions
- Call sdk.views.create instead of update if the view doesn't exist yet.
- Re-fetch the correct view id from the table before updating.
- Confirm the viewId's embedded tableId matches the table you pass.
- Handle the 404 and recreate the view if it was legitimately deleted.
Example fix
// before
await sdk.views.update({ id: staleId, ...view })
// after
const table = await sdk.tables.getTable(tableId)
const exists = Object.values(table.views ?? {}).some(v => isV2(v) && v.id === staleId)
if (!exists) {
await sdk.views.create({ tableId, name: view.name, ...view })
} else {
await sdk.views.update({ id: staleId, ...view })
} Defensive patterns
Strategy: try-catch
Validate before calling
const table = await sdk.tables.getTable(tableId)
if (!Object.values(table.views ?? {}).some(v => isV2(v) && v.id === view.id)) {
await sdk.views.create({ ...view, tableId })
} else {
await sdk.views.update(view)
} Type guard
function viewExistsInTable(view: ViewV2, table: Table): boolean {
return Object.values(table.views ?? {}).some(v => isV2(v) && v.id === view.id)
} Try / catch
try {
await sdk.views.update(view)
} catch (e) {
if (e instanceof HTTPError && e.status === 404) {
await sdk.views.create({ ...view, tableId })
} else { throw e }
} Prevention
- Always fetch fresh view ids from the table before updating
- Use upsert logic (check existence then create/update)
- Confirm the viewId's tableId matches the table being updated
When it happens
Trigger: Calling sdk.views.update(view) where view.id is not present among table.views — view was deleted, id belongs to another table, or update was called instead of create.
Common situations: Client caches a stale view id after deletion; passing a V1 view id; tableId mismatch when moving views; race with a concurrent delete.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Row not found
- Operation not found for this agent
- Custom REST template not found
- Automation not found
- Webhook not found
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/fe3637ac97fadcce.
Report an issue: GitHub.