{"record":{"id":"bc2b746d7795299a","repo":"cube-js/cube","slug":"granularity-timedimension-granularity-does-no","errorCode":null,"errorMessage":"Granularity \"${timeDimension.granularity}\" does not exist in dimension ${timeDimension.dimension}","messagePattern":"Granularity \"(.+?)\" does not exist in dimension (.+?)","errorType":"validation","errorClass":"UserError","httpStatus":null,"severity":"error","filePath":"packages/cubejs-schema-compiler/src/adapter/Granularity.ts","lineNumber":48,"sourceCode":"    private readonly query: BaseQuery,\n    timeDimension: any\n  ) {\n    this.granularity = timeDimension.granularity;\n    this.predefinedGranularity = isPredefinedGranularity(this.granularity);\n    this.queryTimezone = query.timezone || 'UTC';\n    this.origin = moment.tz(query.timezone).startOf('year'); // Defaults to current year start\n\n    if (this.predefinedGranularity) {\n      this.granularityInterval = `1 ${this.granularity}`;\n    } else {\n      const customGranularity = this.query.cacheValue(\n        ['customGranularity', timeDimension.dimension, this.granularity],\n        () => query.cubeEvaluator\n          .resolveGranularity([...query.cubeEvaluator.parsePath('dimensions', timeDimension.dimension), 'granularities', this.granularity])\n      );\n\n      if (!customGranularity) {\n        throw new UserError(`Granularity \"${timeDimension.granularity}\" does not exist in dimension ${timeDimension.dimension}`);\n      }\n\n      if (!customGranularity.interval) {\n        const cause = customGranularity.sql\n          ? 'is defined with \\'sql\\', which is only supported for predefined granularities'\n          : 'has no interval';\n        throw new UserError(`Granularity \"${this.granularity}\" of dimension ${timeDimension.dimension} ${cause}`);\n      }\n\n      this.granularityInterval = customGranularity.interval;\n\n      if (customGranularity.origin) {\n        this.origin = moment.tz(customGranularity.origin, query.timezone);\n      } else if (customGranularity.offset) {\n        // Needed because if interval is week-based, offset is expected to be relative to the start of a week\n        this.fixOriginForWeeksIfNeeded();\n        this.granularityOffset = customGranularity.offset;\n        this.origin = addInterval(this.origin, parseSqlInterval(customGranularity.offset));","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/cube-js/cube/blob/7d981676b36392fec34088b9afab6bdcad40207c/packages/cubejs-schema-compiler/src/adapter/Granularity.ts#L30-L66","documentation":"Granularity constructor resolves the requested time dimension granularity. If it is not a predefined granularity (second..year) and cannot be resolved as a custom granularity defined on the dimension, it throws this UserError naming the granularity and dimension.","triggerScenarios":"A query (REST/GraphQL timeDimensions or SQL API) requests `granularity: 'hour4'` (or any custom name) where the referenced dimension has no matching `granularities` entry, or the granularity name is misspelled.","commonSituations":"Typos in granularity names ('mont' vs 'month'); clients requesting custom granularities before the data model defines them; case-sensitivity mismatches.","solutions":["Fix the granularity name in the query to a predefined one (second, minute, hour, day, week, month, quarter, year).","Define the custom granularity on the dimension with an `interval` (e.g. `granularities: { hour4: { interval: '4 hours' } }`).","Ensure the client version supports custom granularities and the dimension path is correct."],"exampleFix":"// before (query)\ntimeDimensions: [{ dimension: 'Events.timestamp', granularity: 'hour4' }]\n// after (data model)\ndimensions: { timestamp: { type: 'time', sql: `timestamp`, granularities: { hour4: { interval: '4 hours' } } } }","handlingStrategy":"validation","validationCode":"const predefined = ['second','minute','hour','day','week','month','quarter','year'];\nif (!predefined.includes(granularity)) {\n  const dim = dataModel.dimensions[dimName];\n  if (!dim?.granularities?.[granularity]) throw new Error(`Granularity \"${granularity}\" not defined on ${dimName}`);\n}","typeGuard":null,"tryCatchPattern":"try { await cube.load(q) } catch (e) { if (/does not exist in dimension/.test(e.message)) { /* retry with 'day' or fix data model */ } else throw e; }","preventionTips":["Define custom granularities in the data model before clients use them","Centralize granularity names in shared constants","Validate query payloads against the schema in API middleware"],"tags":["granularity","time-dimension","user-error","data-model"],"backgroundTag":"granularity-not-found","analyzedSha":"7d981676b36392fec34088b9afab6bdcad40207c","analyzedAt":"2026-09-02T03:45:10.400Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}