{"record":{"id":"a3d56437fbc90247","repo":"Budibase/budibase","slug":"duplicate-calculation-on-field-schema-field-a3d564","errorCode":null,"errorMessage":"Duplicate calculation on field \"${schema.field}\", calculation type \"${schema.calculationType} distinct\"","messagePattern":"Duplicate calculation on field \"(.+?)\", calculation type \"(.+?) distinct\"","errorType":"validation","errorClass":"HTTPError","httpStatus":400,"severity":"error","filePath":"packages/server/src/sdk/workspace/views/index.ts","lineNumber":141,"sourceCode":"  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) {\n      continue\n    }\n\n    const isDistinct = \"distinct\" in schema\n    if (!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} distinct\"`,\n        400\n      )\n    }\n    seen[schema.field] ??= {} as Record<CalculationType, boolean>\n    seen[schema.field][schema.calculationType] = true\n  }\n}\n\nasync function guardCalculationViewSchema(\n  table: Table,\n  view: Omit<ViewV2, \"id\" | \"version\">\n) {\n  const calculationFields = helpers.views.calculationFields(view)\n\n  guardDuplicateCalculationFields(view)\n  guardDuplicateCountDistinctFields(view)\n","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/sdk/workspace/views/index.ts#L123-L159","documentation":"Companion guard for distinct count aggregates: two COUNT ... distinct calculations on the same field are rejected. Regular duplicates are caught by guardDuplicateCalculationFields; this one covers the distinct-count case that the first guard deliberately skips.","triggerScenarios":"A calculation view schema containing two entries where schema.calculationType is COUNT, \"distinct\" in schema is true, and both target the same schema.field.","commonSituations":"Duplicated distinct-count columns in the builder; generated view JSON repeating a countDistinct field key under two names.","solutions":["Keep at most one distinct COUNT per target field","Drop the duplicate or point it at a different field","Use a non-distinct COUNT alongside the distinct one if both are required"],"exampleFix":"// before\n{ d1: { field: \"email\", calculationType: \"count\", distinct: true }, d2: { field: \"email\", calculationType: \"count\", distinct: true } }\n// after\n{ d1: { field: \"email\", calculationType: \"count\", distinct: true }, total: { field: \"email\", calculationType: \"count\" } }","handlingStrategy":"validation","validationCode":"const seen = new Set()\nfor (const c of Object.values(view.calculations ?? {})) {\n  if (c.calculationType === \"count\" && \"distinct\" in c) {\n    if (seen.has(c.field)) throw new Error(`Duplicate distinct count on ${c.field}`)\n    seen.add(c.field)\n  }\n}","typeGuard":null,"tryCatchPattern":"try { await sdk.views.create(tableId, view) }\ncatch (e) {\n  if (e instanceof HTTPError && e.status === 400 && /distinct/.test(e.message)) {\n    // drop duplicate distinct count entries then retry\n  } else throw e\n}","preventionTips":["Allow only one distinct COUNT per column in the UI","Deduplicate countDistinct entries programmatically","Validate before POST/PUT, not after"],"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"}