Budibase/budibase · error · HTTPError
Webhook schema can only be built in development
Error message
Webhook schema can only be built in development
What it means
Budibase webhooks define their request body schema against a development copy of the workspace. When the webhook schema build endpoint is called for a workspace whose ID is not a development workspace ID, assertSchemaWorkspace rejects it with HTTP 400. This prevents mutating published/prod app definitions from webhook schema sync.
Source
Thrown at packages/server/src/api/controllers/webhook.ts:72
ctx.body = {
message: "Webhook created successfully",
webhook,
}
}
export async function destroy(ctx: Ctx<void, DeleteWebhookResponse>) {
ctx.body = await sdk.automations.webhook.destroy(
ctx.params.id,
ctx.params.rev
)
}
const assertSchemaWorkspace = (instance: string) => {
if (dbCore.isDevWorkspaceID(instance)) {
return
}
throw new HTTPError("Webhook schema can only be built in development", 400)
}
const updateWebhookSchema = async (
body: BuildWebhookSchemaRequest,
webhook: Webhook,
db: ReturnType<typeof context.getWorkspaceDB>
) => {
webhook.bodySchema = toJsonSchema(body)
if (webhook.action.type === WebhookActionType.AUTOMATION) {
const automation = await db.tryGet<Automation>(webhook.action.target)
if (!automation) {
throw new HTTPError("Automation not found", 404)
}
const autoOutputs = automation.definition.trigger.schema.outputs
const properties = webhook.bodySchema?.properties
autoOutputs.properties = {
body: autoOutputs.properties.body,
}View on GitHub (pinned to a81a902e9a)
Solutions
- Run the schema build against the development workspace ID for the app (the appid ending in _dev).
- If the change must reach prod, redeploy/publish the app after building the schema in dev.
- Check that the instance/appId parameter in the request URL is the dev app ID, not the prod one.
- If automation-driven, update the automation config to use the dev app ID for schema sync operations.
Example fix
// before
await api.post(`/api/webhooks/schema/${prodAppId}/${webhookId}`)
// after
await api.post(`/api/webhooks/schema/${devAppId}/${webhookId}`) // appId ending in _dev Defensive patterns
Strategy: validation
Validate before calling
import { isDevWorkspaceID } from "@budibase/backend-core/db";
if (!isDevWorkspaceID(appId)) {
throw new Error("Schema build must target the dev workspace (appId ending in _dev)")
} Type guard
const isDev = (appId: string): boolean => isDevWorkspaceID(appId)
Try / catch
try {
await buildWebhookSchema(appId, webhookId)
} catch (e) {
if (e.status === 400 && /development/.test(e.message)) {
appId = toDevAppId(appId); return retry(appId, webhookId)
}
throw e
} Prevention
- Always store and use the dev app ID for schema-sync operations.
- Publish to prod via deploy rather than mutating prod docs directly.
- Centralize webhook schema build calls behind a helper that asserts dev app IDs.
- Log the app ID used so mismatches are obvious in failures.
When it happens
Trigger: Calling buildSchema (POST webhook schema build) with ctx.params.instance set to a published/prod (non-dev) workspace ID.
Common situations: Pointing an external service at a prod app's webhook schema-build URL; copying a webhook ID from a dev app and using it against the deployed app; automated tooling that iterates all workspaces without filtering dev ones.
Related errors
- workspaceId is required
- Destination workspace does not exist
- User ID missing
- User ID or revision missing
- User revision missing
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/32fd7ec16a52afbd.
Report an issue: GitHub.