Budibase/budibase · error · HTTPError
Calculation fields are not allowed in non-calculation views
Error message
Calculation fields are not allowed in non-calculation views
What it means
guardViewSchema rejects view payloads where a NON-calculation view includes calculation fields. Calculation fields (aggregations like sums/counts) are only valid on calculation views; placing them on a regular view is an invalid config, so a 400 is thrown.
Source
Thrown at packages/server/src/sdk/workspace/views/index.ts:226
throw new HTTPError(
`Grouping by fields of type "${targetSchema.type}" is not supported`,
400
)
}
}
}
async function guardViewSchema(
tableId: string,
view: Omit<ViewV2, "id" | "version">
) {
const table = await sdk.tables.getTable(tableId)
if (helpers.views.isCalculationView(view)) {
await guardCalculationViewSchema(table, view)
} else {
if (helpers.views.hasCalculationFields(view)) {
throw new HTTPError(
"Calculation fields are not allowed in non-calculation views",
400
)
}
}
await checkReadonlyFields(table, view)
if (!helpers.views.isCalculationView(view)) {
checkRequiredFields(table, view)
}
// Falling back to the table's display column here means a view whose
// display column no longer exists can still be saved, rather than every
// save being rejected by the display column check
ensureValidPrimaryDisplay(view, table)
checkDisplayField(view)View on GitHub (pinned to a81a902e9a)
Solutions
- Remove all calculation fields from the view schema.
- Or mark/create the view as a calculation view if aggregations are intended.
- Or move the aggregation fields into a separate calculation view.
Example fix
// before
const view = { name: "v", type: "table", schema: { total: { visible: true, readonly: false, /* calculation field */ } } }
// after
const view = { name: "v", type: "table", schema: { total: { visible: true, readonly: false } } } Defensive patterns
Strategy: validation
Validate before calling
if (!helpers.views.isCalculationView(view) && helpers.views.hasCalculationFields(view)) {
Object.keys(view.schema).forEach(k => delete view.schema[k])
} Type guard
function hasNoCalcFields(view: Omit<ViewV2, "id" | "version">): boolean {
return helpers.views.isCalculationView(view) || !helpers.views.hasCalculationFields(view)
} Try / catch
try {
await sdk.views.update(view)
} catch (e) {
if (e instanceof HTTPError && e.status === 400 && e.message === "Calculation fields are not allowed in non-calculation views") {
// strip calc fields and retry once
} else { throw e }
} Prevention
- Only add calculation fields to views created as calculation views
- When changing view type, rebuild the schema from scratch
- Never copy schemas between calculation and plain views verbatim
When it happens
Trigger: sdk.views.create or sdk.views.update called with a view where helpers.views.isCalculationView(view) is false but helpers.views.hasCalculationFields(view) is true (view.schema entries flagged as calculation fields).
Common situations: Manually editing exported view JSON; API clients copying schema from a calculation view onto a plain view; UI state drift after switching view type without stripping calculation fields.
Related errors
- Grouping by fields of type "${targetSchema.type}" is not sup
- Field "${field}" is not valid for the requested table
- Field "${field}" must be visible if you want to make it read
- You can't hide "${view.primaryDisplay}" because it is the di
- You can't hide "${field.name}" because it is a required fiel
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/428693dab6d40c2b.
Report an issue: GitHub.