cube-js/cube · critical

Cube API client is not provided

Error message

Cube API client is not provided

What it means

useCubeQuery's internal fetch() resolves the API client from options.cubeApi or the CubeContext provider. If neither supplies a CubeApi instance, it throws because there is no client to send the query to.

Source

Thrown at packages/cubejs-client-react/src/hooks/cube-query.ts:91

  const [isLoading, setLoading] = useState(!options.skip);
  const [resultSet, setResultSet] = useState<ResultSet | null>(null);
  const [progress, setProgress] = useState<ProgressResponse | null>(null);
  const [error, setError] = useState<Error | null>(null);
  const context = useContext(CubeContext);

  let subscribeRequest: UnsubscribeObj | null = null;

  // `progressResponse` is not part of the public `ProgressResult` API
  const progressCallback: ProgressCallback = (progressResult) => setProgress(
    (progressResult as unknown as ProgressResultWithResponse).progressResponse
  );

  async function fetch() {
    const { resetResultSetOnChange } = options;
    const cubeApi = options.cubeApi || context?.cubeApi;

    if (!cubeApi) {
      throw new Error('Cube API client is not provided');
    }

    if (resetResultSetOnChange) {
      setResultSet(null);
    }

    setError(null);
    setLoading(true);

    try {
      const response = await cubeApi.load(query, {
        mutexObj: mutexRef.current,
        mutexKey: 'query',
        progressCallback,
        castNumerics: Boolean(typeof options.castNumerics === 'boolean' ? options.castNumerics : context?.options?.castNumerics),
        ...(options.cache ? { cache: options.cache } : {}),
      });

View on GitHub (pinned to 7d981676b3)

Solutions

  1. Wrap the component tree in <CubeProvider cubeApi={cubeApi('token', { apiUrl })}>.
  2. Pass the client directly: useCubeQuery(query, { cubeApi }).
  3. Ensure the hook is used in a child component of CubeProvider, not a sibling/parent.
  4. Fix ordering issues where a context consumer reads context before the provider sets cubeApi.

Example fix

// before
const { resultSet } = useCubeQuery(query); // no provider, no cubeApi
// after
const [cubeApi] = useState(() => cube('CUBEJS_TOKEN', { apiUrl: 'http://localhost:4000/cubejs-api/v1' }));
const { resultSet } = useCubeQuery(query, { cubeApi });
Defensive patterns

Strategy: validation

Validate before calling

if (!options.cubeApi && !context?.cubeApi) {
  throw new Error('useCubeQuery requires a cubeApi via options or CubeProvider');
}

Type guard

function isCubeApi(v: unknown): v is { load: Function; sql: Function } {
  return !!v && typeof v === 'object' && typeof (v as any).load === 'function';
}

Try / catch

try {
  const { resultSet } = useCubeQuery(query);
} catch (e) {
  if (e.message === 'Cube API client is not provided') {
    console.error('Wrap your app in <CubeProvider cubeApi={...}> or pass options.cubeApi');
  }
}

Prevention

When it happens

Trigger: Calling useCubeQuery outside a <CubeProvider> without passing { cubeApi } in options; passing cubeApi: undefined; rendering the hook before context is populated.

Common situations: Forgot to wrap the app in <CubeProvider cubeApi={cubeApi(...)}>; using the hook in a component tree that sits above the provider; dynamically rendering a chart component that imports the hook without a client; testing the hook without a wrapper.

Related errors


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