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

  1. Run the schema build against the development workspace ID for the app (the appid ending in _dev).
  2. If the change must reach prod, redeploy/publish the app after building the schema in dev.
  3. Check that the instance/appId parameter in the request URL is the dev app ID, not the prod one.
  4. 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

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


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