{"record":{"id":"a513f1fc25a9bf1c","repo":"cube-js/cube","slug":"time-sql-is-not-defined","errorCode":null,"errorMessage":"time.sql is not defined","messagePattern":"time\\.sql is not defined","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cubejs-schema-compiler/src/extensions/Funnels.ts","lineNumber":13,"sourceCode":"import inflection from 'inflection';\nimport { AbstractExtension } from './extension.abstract';\n\nexport class Funnels extends AbstractExtension {\n  // TODO check timeToConvert is absent on first step\n  // TODO name can be a title\n  public eventFunnel(funnelDefinition) {\n    if (!funnelDefinition.userId || !funnelDefinition.userId.sql) {\n      throw new Error('userId.sql is not defined'); // TODO schema check\n    }\n\n    if (!funnelDefinition.time || !funnelDefinition.time.sql) {\n      throw new Error('time.sql is not defined'); // TODO schema check\n    }\n\n    if (!funnelDefinition.steps || !funnelDefinition.steps.length) {\n      throw new Error('steps are not defined'); // TODO schema check\n    }\n\n    return this.cubeFactory({\n      sql: () => {\n        const eventJoin =\n          funnelDefinition.steps.map((s, i) => this.eventCubeJoin(funnelDefinition, s, funnelDefinition.steps[i - 1]));\n        const userIdColumnsAndTime =\n          funnelDefinition.steps.map(s => `${this.eventsTableName(s)}.user_id ${this.stepUserIdColumnName(s)}`)\n            .concat([`${this.eventsTableName(funnelDefinition.steps[0])}.t`]).join(',\\n');\n        return `WITH joined_events AS (\n    select\n    ${userIdColumnsAndTime}\n    FROM\n${eventJoin.join('\\nLEFT JOIN\\n')}","sourceCodeStart":1,"sourceCodeEnd":31,"githubUrl":"https://github.com/cube-js/cube/blob/7d981676b36392fec34088b9afab6bdcad40207c/packages/cubejs-schema-compiler/src/extensions/Funnels.ts#L1-L31","documentation":"The Funnels schema extension requires every funnel definition to declare time.sql, which provides the event timestamp used to order funnel steps. The error fires in eventFunnel when the time property is missing or has no sql — it is a plain schema validation guard (marked TODO for a proper schema check), not a runtime query failure.","triggerScenarios":"Calling eventFunnel with funnelDefinition.time undefined or not containing a sql property (e.g. a plain string or an empty object).","commonSituations":"Funnel definitions copied from old examples; forgetting to add the timestamp field; passing a member reference as a string instead of `{ sql: ... }`.","solutions":["Add time: { sql: `${CUBE}.timestamp` } (or your event time column) to the funnel definition","Confirm the property is named `time`, not `timestamp` or `date`","Ensure the sql value resolves against the event cube's columns"],"exampleFix":"// before\neventFunnel({\n  userId: { sql: `${CUBE}.user_id` },\n  time: 'events.ts'\n});\n// after\neventFunnel({\n  userId: { sql: `${CUBE}.user_id` },\n  time: { sql: `${CUBE}.timestamp` }\n});","handlingStrategy":"validation","validationCode":"const hasTimeSql = (f) => !!f && !!f.time && typeof f.time.sql !== 'undefined';","typeGuard":"const hasTimeSql = (f) => typeof f?.time?.sql === 'string' || typeof f?.time?.sql === 'function';","tryCatchPattern":"try {\n  funnelCube.eventFunnel(def);\n} catch (e) {\n  if (e.message === 'time.sql is not defined') {\n    console.error('Add time: { sql: `${CUBE}.timestamp` } to the funnel definition');\n  }\n  throw e;\n}","preventionTips":["Include time: { sql: ... } in every funnel definition","Validate the whole funnel object before calling eventFunnel","Name the field exactly `time` — not timestamp or date"],"tags":["funnel","schema-validation","extension"],"backgroundTag":"missing-required-argument","analyzedSha":"7d981676b36392fec34088b9afab6bdcad40207c","analyzedAt":"2026-09-02T03:45:10.400Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}