cube-js/cube · error · Error
userId.sql is not defined
Error message
userId.sql is not defined
What it means
The Funnels schema extension requires funnelDefinition.userId to be an object with a sql property. It throws when userId is missing entirely or lacks .sql, since the extension cannot build the user-identity join for the funnel SQL without it.
Source
Thrown at packages/cubejs-schema-compiler/src/extensions/Funnels.ts:9
import inflection from 'inflection';
import { AbstractExtension } from './extension.abstract';
export class Funnels extends AbstractExtension {
// TODO check timeToConvert is absent on first step
// TODO name can be a title
public eventFunnel(funnelDefinition) {
if (!funnelDefinition.userId || !funnelDefinition.userId.sql) {
throw new Error('userId.sql is not defined'); // TODO schema check
}
if (!funnelDefinition.time || !funnelDefinition.time.sql) {
throw new Error('time.sql is not defined'); // TODO schema check
}
if (!funnelDefinition.steps || !funnelDefinition.steps.length) {
throw new Error('steps are not defined'); // TODO schema check
}
return this.cubeFactory({
sql: () => {
const eventJoin =
funnelDefinition.steps.map((s, i) => this.eventCubeJoin(funnelDefinition, s, funnelDefinition.steps[i - 1]));
const userIdColumnsAndTime =
funnelDefinition.steps.map(s => `${this.eventsTableName(s)}.user_id ${this.stepUserIdColumnName(s)}`)
.concat([`${this.eventsTableName(funnelDefinition.steps[0])}.t`]).join(',\n');
return `WITH joined_events AS (View on GitHub (pinned to 7d981676b3)
Solutions
- Add a userId object with a sql function/property to the funnel definition: userId: { sql: `${CUBE}.user_id` }
- Verify the spelling — userId must be camelCase exactly
- If userId should come from a shared definition, factor it into the cube and reference it correctly
Example fix
// before
eventFunnel({
userId: 'users.id',
...
});
// after
eventFunnel({
userId: { sql: `${CUBE}.user_id` },
...
}); Defensive patterns
Strategy: validation
Validate before calling
const hasUserIdSql = (f) => !!f && !!f.userId && typeof f.userId.sql !== 'undefined';
Type guard
const hasUserIdSql = (f) => typeof f?.userId?.sql === 'string' || typeof f?.userId?.sql === 'function';
Try / catch
try {
funnelCube.eventFunnel(def);
} catch (e) {
if (e.message === 'userId.sql is not defined') {
console.error('Add userId: { sql: `${CUBE}.user_id` } to the funnel definition');
}
throw e;
} Prevention
- Always define userId as an object with sql, never a bare string
- Keep a funnel definition template with userId/time/steps pre-filled
- Type-check funnel definitions in TypeScript projects
When it happens
Trigger: Defining an eventFunnel whose userId is undefined, null, or set to a string/plain value instead of `{ sql: ... }`.
Common situations: Copy-pasting funnel examples without filling in userId; passing a raw member name instead of an object with sql; YAML funnels where userId was left empty.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- time.sql is not defined
- steps are not defined
- Invalid query format: ${error.message || error.toString()}
- Subquery measure ${m.expressionName} should reference at lea
- List of references and a function are expected in form: dynR
AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02).
Data as JSON: /api/errors/be748213e9b8ba45.
Report an issue: GitHub.