{"record":{"id":"1811bfad12e36e35","repo":"Budibase/budibase","slug":"duplicate-calculation-on-field-schema-field","errorCode":null,"errorMessage":"Duplicate calculation on field \"${schema.field}\", calculation type \"${schema.calculationType}\"","messagePattern":"Duplicate calculation on field \"(.+?)\", calculation type \"(.+?)\"","errorType":"http","errorClass":"HTTPError","httpStatus":400,"severity":"error","filePath":"packages/server/src/sdk/workspace/views/index.ts","lineNumber":112,"sourceCode":"  const tableId = getTableIdFromViewId(viewId)\n  return !isExternalTableID(tableId)\n}\n\nfunction guardDuplicateCalculationFields(view: Omit<ViewV2, \"id\" | \"version\">) {\n  const seen: Record<string, Record<CalculationType, boolean>> = {}\n  const calculationFields = helpers.views.calculationFields(view)\n  for (const name of Object.keys(calculationFields)) {\n    const schema = calculationFields[name]\n    const isCount = schema.calculationType === CalculationType.COUNT\n    const isDistinct = \"distinct\" in schema\n\n    if (isCount && isDistinct) {\n      // We do these separately.\n      continue\n    }\n\n    if (seen[schema.field]?.[schema.calculationType]) {\n      throw new HTTPError(\n        `Duplicate calculation on field \"${schema.field}\", calculation type \"${schema.calculationType}\"`,\n        400\n      )\n    }\n    seen[schema.field] ??= {} as Record<CalculationType, boolean>\n    seen[schema.field][schema.calculationType] = true\n  }\n}\n\nfunction guardDuplicateCountDistinctFields(\n  view: Omit<ViewV2, \"id\" | \"version\">\n) {\n  const seen: Record<string, Record<CalculationType, boolean>> = {}\n  const calculationFields = helpers.views.calculationFields(view)\n  for (const name of Object.keys(calculationFields)) {\n    const schema = calculationFields[name]\n    const isCount = schema.calculationType === CalculationType.COUNT\n    if (!isCount) {","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/sdk/workspace/views/index.ts#L94-L130","documentation":"Validation guard for calculation views: each non-count-distinct combination of target field and calculation type may appear only once across the view's calculation fields. A duplicate (same field, same calculationType) is rejected with 400.","triggerScenarios":"Creating/updating a view whose calculation schema defines two named calculation fields pointing at the same schema.field with the same calculationType (excluding COUNT distinct, handled separately).","commonSituations":"Builder duplicating a calculation column without changing target field; scripted view generation producing repeated aggregates like sum(revenue) twice under different names.","solutions":["Remove or rename the duplicate calculation entry so each field+calculationType pair is unique","Give one of the duplicates a different calculationType if both are needed","Distinct COUNT duplicates should use the distinct form, which is tracked separately"],"exampleFix":"// before\ncalculations: { rev1: { field: \"revenue\", calculationType: \"sum\" }, rev2: { field: \"revenue\", calculationType: \"sum\" } }\n// after\ncalculations: { rev_sum: { field: \"revenue\", calculationType: \"sum\" }, rev_avg: { field: \"revenue\", calculationType: \"avg\" } }","handlingStrategy":"validation","validationCode":"const seen = new Set()\nfor (const c of Object.values(view.calculations ?? {})) {\n  if (c.calculationType === \"count\" && \"distinct\" in c) continue\n  const key = `${c.field}:${c.calculationType}`\n  if (seen.has(key)) throw new Error(`Duplicate calculation: ${key}`)\n  seen.add(key)\n}","typeGuard":null,"tryCatchPattern":"try { await sdk.views.create(tableId, view) }\ncatch (e) {\n  if (e instanceof HTTPError && e.status === 400 && /Duplicate calculation/.test(e.message)) {\n    // dedupe view.calculations then retry\n  } else throw e\n}","preventionTips":["Enforce unique field+calculationType pairs when building the view UI","Deduplicate generated calculation schemas before submitting","Add client-side validation mirroring the server guard"],"tags":["http-400","views","validation","calculations"],"backgroundTag":"schema-validation-failed","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}