Budibase/budibase · error
This action cannot be performed for production apps
Error message
This action cannot be performed for production apps
What it means
syncWorkspace replicates a production workspace into its development counterpart. It explicitly rejects production workspace ids — this action only makes sense from a dev app — throwing a plain Error when dbCore.isProdWorkspaceID(workspaceId) is true.
Source
Thrown at packages/server/src/sdk/workspace/workspaces/sync.ts:171
export async function syncUsersAcrossWorkspaces(userIds: string[]) {
const devWorkspaceIds = await dbCore.getDevWorkspaceIDs()
await syncUsersAgainstWorkspaces(userIds, devWorkspaceIds)
}
export async function syncWorkspace(
workspaceId: string,
opts?: { automationOnly?: boolean }
): Promise<{ message: string }> {
if (env.DISABLE_AUTO_PROD_APP_SYNC) {
return {
message:
"App sync disabled. You can reenable with the DISABLE_AUTO_PROD_APP_SYNC environment variable.",
}
}
if (dbCore.isProdWorkspaceID(workspaceId)) {
throw new Error("This action cannot be performed for production apps")
}
// replicate prod to dev
const prodWorkspaceId = dbCore.getProdWorkspaceID(workspaceId)
// specific case, want to make sure setup is skipped
const prodDb = context.getProdWorkspaceDB({ skip_setup: true })
const exists = await prodDb.exists()
let error
if (exists) {
const replication = new dbCore.Replication({
source: prodWorkspaceId,
target: workspaceId,
})
try {
const replOpts = replication.appReplicateOpts()
if (opts?.automationOnly) {View on GitHub (pinned to a81a902e9a)
Solutions
- Convert the id first: call dbCore.getDevWorkspaceID(prodId) and pass the dev id
- Guard the call: only invoke when !dbCore.isProdWorkspaceID(workspaceId)
- Fix the caller to source the dev workspace id (e.g. from the app metadata rather than the published URL)
Example fix
// before await sync.syncWorkspace(appId) // after const devId = dbCore.isProdWorkspaceID(appId) ? dbCore.getDevWorkspaceID(appId) : appId await sync.syncWorkspace(devId)
Defensive patterns
Strategy: validation
Validate before calling
if (dbCore.isProdWorkspaceID(workspaceId)) {
workspaceId = dbCore.getDevWorkspaceID(workspaceId)
} Type guard
function isDevWorkspace(id) {
return !dbCore.isProdWorkspaceID(id)
} Try / catch
try {
await sync.syncWorkspace(devId)
} catch (e) {
if (e?.message?.includes('cannot be performed for production apps')) {
// caller passed a prod id; convert and retry
} else throw e
} Prevention
- Always derive the dev id with getDevWorkspaceID before syncing
- Never source workspace ids from published app URLs
- Guard sync entry points with isProdWorkspaceID checks
When it happens
Trigger: Calling syncWorkspace/initDeployedApp/sync/syncDevApp with a production workspace id (one ending in the prod suffix, e.g. workspaceId without '-dev', or explicitly derived via getProdWorkspaceID).
Common situations: Automation or scripts that resolve the app id from a published app URL (which uses the prod id); calling sync on the wrong side of dev/prod; wiring a deploy hook to sync using the prod id by mistake.
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/5bd1b006dd81a9dc.
Report an issue: GitHub.