cube-js/cube · error · UserError
Empty Python atom_expr node: ${node.constructor.name}: ${nod
Error message
Empty Python atom_expr node: ${node.constructor.name}: ${node.getText()} What it means
Thrown by PythonParser.transpileToJs() when an Atom_exprContext (attribute access / call chain like obj.method()) produces zero children, i.e. the visitor reduced every child away and there is nothing to build an expression from. This is an internal-consistency failure of the transpiler given unusual Python syntax inside atom_expr.
Source
Thrown at packages/cubejs-schema-compiler/src/parser/PythonParser.ts:182
}
return t.templateLiteral(children.filter(c => c.type === 'TemplateElement'), children.filter(c => c.type !== 'TemplateElement'));
} else if (node instanceof Atom_exprContext) {
if (children.length === 1) {
return children[0];
} else if (children.length > 1) {
let expr = children[0];
for (let i = 1; i < children.length; i++) {
if (children[i].call) {
expr = t.callExpression(expr, children[i].call);
} else if (children[i].identifier) {
expr = t.memberExpression(expr, children[i].identifier);
} else {
throw new Error(`Unexpected trailer child: ${children[i]}`);
}
}
return expr;
} else {
throw new UserError(`Empty Python atom_expr node: ${node.constructor.name}: ${node.getText()}`);
}
} else if (node instanceof AtomContext) {
const name = node.NAME();
const stringList = node.STRING_list();
const number = node.NUMBER();
if (name) {
return t.identifier(name.getText());
} else if (stringList && stringList.length) {
return t.stringLiteral(stringList.map(s => this.stripQuotes(s.getText())).join(''));
} else if (number) {
const numText = number.getText();
const numValue = parseFloat(numText);
return t.numericLiteral(numValue);
} else {
return singleNodeReturn();
}
} else if (node instanceof CallArgumentsContext) {View on GitHub (pinned to 7d981676b3)
Solutions
- Locate the code from node.getText() in the error message and simplify it to plain identifier/attribute/call syntax
- Remove async/await, yield, or generator constructs from the data model file
- Fix any preceding syntax errors in the file (error recovery can create empty nodes)
- Report as a bug with the offending snippet if standard syntax triggers it
Example fix
// before (cubes.py) await cube_config.load() // after load(cube_config)
Defensive patterns
Strategy: try-catch
Validate before calling
// Guard degenerate trees by pre-parsing with error collection
const parser = new PythonParser(source);
if (!parser.canParse()) throw new Error('Fix syntax errors before transpiling'); Try / catch
try {
transpileToJs();
} catch (e) {
if (e instanceof UserError && e.message.startsWith('Empty Python atom_expr node')) {
throw new Error(`Unsupported/empty expression in model: ${e.message}`);
}
throw e;
} Prevention
- Fix all syntax errors first — ANTLR recovery produces empty nodes
- Avoid async/await, yield and exotic expressions in model files
- Keep model Python minimal and test it with a plain interpreter
- If valid syntax triggers it, report with the snippet from the message
When it happens
Trigger: parsePythonAndTranspileToJs visits an Atom_exprContext whose visitNode children array is empty — e.g. atom_expr containing only constructs the visitor returns undefined for, or malformed/partially parsed input from a failed ANTLR recovery.
Common situations: Rare; usually follows exotic Python in the data model (await expressions, yield, complex trailers) or a parser error-recovery path that produced a degenerate tree. Appears when compiling cubes.py during schema compile.
Related errors
- Unsupported Python multiple children node: ${node.constructo
- Unsupported Python Trailer children node: ${node.constructor
- Unsupported Python vfpdef children node: ${node.constructor.
- '${fileName}' transpiling failed
- Python Parsing Error: ${this.errors.map(({ msg, column, line
AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02).
Data as JSON: /api/errors/2b99cf016fef5fb5.
Report an issue: GitHub.