cube-js/cube · error · UserError
${context} must be a single reference, not an array
Error message
${context} must be a single reference, not an array What it means
CubeSymbols evaluates a function that must return a single member reference (a string) during schema compilation. If the function returns an array instead, the compiler cannot use it where a lone reference is required, so it throws this UserError. It guards APIs like join paths or reference getters that expect exactly one dimension/measure name.
Source
Thrown at packages/cubejs-schema-compiler/src/compiler/CubeSymbols.ts:1247
// For any branch of return type that can can contain just an object it's OK to return string
return arrayOrSingle.toString() as any;
}
const references: Array<string> = arrayOrSingle.map(p => p.toString());
// arrayOrSingle is of type `T`, and we just checked that it is an array
// Which means that both `T` and result must be arrays
// For any branch of return type that can contain array it's OK to return array
return options.originalSorting ? references : R.sortBy(R.identity, references) as any;
}
public evaluateReference(
cube: string,
referencesFn: (...args: Array<unknown>) => ToString,
context: string
): string {
const result = this.evaluateReferences(cube, referencesFn);
if (Array.isArray(result)) {
throw new UserError(`${context} must be a single reference, not an array`);
}
return result;
}
public pathFromArray(array: string[]): string {
return array.join('.');
}
/**
* Split join path to member to join hint and member path: `A.B.C.D.E.dim` => `[A, B, C, D, E]` + `E.dim`
*/
public static joinHintFromPath(path: string): { path: string, joinHint: string[] } {
const parts = path.split('.');
if (parts.length > 2) {
// Path contains join path
const joinHint = parts.slice(0, -1);
return {View on GitHub (pinned to 7d981676b3)
Solutions
- Change the function to return a single string reference instead of an array (e.g. `return a.id` not `[a.id]`).
- If you need multiple references, move them to the correct multi-value API (e.g. the member list side of the join definition).
- Check the data model docs for the exact expected signature of the option you are passing.
Example fix
// before
joins: {
Users: { sql: '\${CUBE}.userId = \${Users.id}', references: (a, b) => [a.userId, b.id] }
}
// after
joins: {
Users: { sql: '\${CUBE}.userId = \${Users.id}', references: (a, b) => [a.userId, b.id] } // keep arrays in references;
// for single-reference APIs: (a) => a.userId
} Defensive patterns
Strategy: validation
Validate before calling
const refs = myReferencesFn(cubeA, cubeB);
if (Array.isArray(refs)) {
throw new Error('referencesFn must return a single string reference, got array');
} Type guard
function isSingleReference(v) { return typeof v === 'string'; } Try / catch
try { await compiler.compile(); } catch (e) { if (e instanceof UserError && /must be a single reference, not an array/.test(e.message)) { /* fix schema fn */ } else throw e; } Prevention
- Type reference-returning functions as returning string, not string[]
- Keep arrays only in options documented as multi-value (e.g. join references lists)
- Run schema compilation in CI to catch shape mistakes early
When it happens
Trigger: A schema function passed to CubeSymbols (e.g. a references function, join SQL, or referencesFn returning a member name) returns an array of strings instead of a single string. E.g. a join definition whose SQL or referenced member resolves to `[...]`.
Common situations: Defining a join with `references: (a, b) => [a.id, b.id]` style multi-value return where a single reference is expected; copying an array variable into a context expecting one member name; TypeScript-less JS schemas where the wrong shape slips through.
Related errors
- ${cubeName}${refProperty ? `.${refProperty}` : ''}.${propert
- Can't parse date: '${from}'
- Can't parse date: '${to}'
- Can't parse date: '${dateString}'
- Expected one parameter but nothing found
AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02).
Data as JSON: /api/errors/4b900e66aaf001e2.
Report an issue: GitHub.