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

  1. Add a userId object with a sql function/property to the funnel definition: userId: { sql: `${CUBE}.user_id` }
  2. Verify the spelling — userId must be camelCase exactly
  3. 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

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


AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02). Data as JSON: /api/errors/be748213e9b8ba45. Report an issue: GitHub.