{"record":{"id":"bbe5694a581400e3","repo":"cube-js/cube","slug":"questdb-custom-granularity-has-an-unparseable-orig","errorCode":null,"errorMessage":"QuestDB custom granularity has an unparseable origin: ${origin}","messagePattern":"QuestDB custom granularity has an unparseable origin: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cubejs-questdb-driver/src/QuestQuery.ts","lineNumber":138,"sourceCode":"\n  public dateBin(interval: string, source: string, origin: string): string {\n    const { stride, unit, count } = this.questFloorStride(interval);\n    // timestamp_floor(stride, ts, origin) only buckets forward from `origin`, so\n    // an origin later than the data collapses every row into a single bucket.\n    // Shift `origin` back by a whole number of strides (which preserves the bin\n    // phase, as flooring is periodic modulo the stride) to just before a fixed\n    // anchor that precedes any realistic data.\n    const shift = this.dateBinOriginShift(origin, unit, count);\n    const shiftedOrigin = shift > 0\n      ? `dateadd('${unit}', ${-shift}, cast('${origin}' as timestamp))`\n      : `cast('${origin}' as timestamp)`;\n\n    return `timestamp_floor('${stride}', ${source}, ${shiftedOrigin})`;\n  }\n\n  private dateBinOriginShift(origin: string, unit: string, count: number): number {\n    const parsedOrigin = moment.utc(origin);\n    if (!parsedOrigin.isValid()) {\n      throw new Error(`QuestDB custom granularity has an unparseable origin: ${origin}`);\n    }\n\n    const anchor = moment.utc(DATE_BIN_ORIGIN_ANCHOR);\n    const strides = Math.ceil(parsedOrigin.diff(anchor, QUEST_UNIT_TO_MOMENT[unit]) / count);\n\n    const shift = strides > 0 ? strides * count : 0;\n    if (shift > INT32_MAX) {\n      throw new Error(\n        `QuestDB cannot anchor custom granularity '${count} ${unit}': origin shift ${shift} exceeds dateadd()'s 32-bit range`\n      );\n    }\n\n    return shift;\n  }\n\n  private questFloorStride(interval: string): { stride: string, unit: string, count: number } {\n    const [duration, type] = this.parseInterval(interval);","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/cube-js/cube/blob/7d981676b36392fec34088b9afab6bdcad40207c/packages/cubejs-questdb-driver/src/QuestQuery.ts#L120-L156","documentation":"For custom granularities, QuestQuery.dateBinOriginShift parses the user-supplied origin timestamp with moment.utc to compute an offset from a fixed anchor. If the origin string cannot be parsed into a valid date, the driver throws instead of producing broken SQL.","triggerScenarios":"Calling shift/dateBin with a custom-granularity origin that is not a valid UTC date string (empty string, wrong format, localized date text).","commonSituations":"A data model defining a custom granularity with an origin written in a non-ISO format (e.g. '01/02/2024' ambiguity aside, or 'Jan 2nd 2024' with locale issues); origin left undefined and stringified.","solutions":["Provide the origin as an ISO 8601 UTC string, e.g. '2024-01-01T00:00:00Z'","Validate the origin value in your schema/config before compiling queries","Remove the custom origin to fall back to the default anchor"],"exampleFix":"// before\norigin: 'January 1st, 2024'\n// after\norigin: '2024-01-01T00:00:00Z'","handlingStrategy":"validation","validationCode":"if (!moment.utc(origin, moment.ISO_8601, true).isValid()) throw new Error(`origin ${origin} must be a valid ISO 8601 UTC date`);","typeGuard":"function isValidIsoOrigin(s) { return typeof s === 'string' && moment.utc(s, moment.ISO_8601, true).isValid(); }","tryCatchPattern":"try { await cube.query(...); } catch (e) { if (e.message.includes('unparseable origin')) { /* correct the origin in the data model and retry */ } throw e; }","preventionTips":["Always express custom-granularity origins as ISO 8601 UTC strings","Validate data model config at load time","Avoid locale-dependent date strings in schemas"],"tags":["date-parsing","questdb","custom-granularity"],"backgroundTag":"invalid-date-format","analyzedSha":"7d981676b36392fec34088b9afab6bdcad40207c","analyzedAt":"2026-09-02T03:45:10.400Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}