{"record":{"id":"2b99cf016fef5fb5","repo":"cube-js/cube","slug":"empty-python-atom-expr-node-node-constructor-na","errorCode":null,"errorMessage":"Empty Python atom_expr node: ${node.constructor.name}: ${node.getText()}","messagePattern":"Empty Python atom_expr node: (.+?): (.+?)","errorType":"exception","errorClass":"UserError","httpStatus":null,"severity":"error","filePath":"packages/cubejs-schema-compiler/src/parser/PythonParser.ts","lineNumber":182,"sourceCode":"          }\n          return t.templateLiteral(children.filter(c => c.type === 'TemplateElement'), children.filter(c => c.type !== 'TemplateElement'));\n        } else if (node instanceof Atom_exprContext) {\n          if (children.length === 1) {\n            return children[0];\n          } else if (children.length > 1) {\n            let expr = children[0];\n            for (let i = 1; i < children.length; i++) {\n              if (children[i].call) {\n                expr = t.callExpression(expr, children[i].call);\n              } else if (children[i].identifier) {\n                expr = t.memberExpression(expr, children[i].identifier);\n              } else {\n                throw new Error(`Unexpected trailer child: ${children[i]}`);\n              }\n            }\n            return expr;\n          } else {\n            throw new UserError(`Empty Python atom_expr node: ${node.constructor.name}: ${node.getText()}`);\n          }\n        } else if (node instanceof AtomContext) {\n          const name = node.NAME();\n          const stringList = node.STRING_list();\n          const number = node.NUMBER();\n\n          if (name) {\n            return t.identifier(name.getText());\n          } else if (stringList && stringList.length) {\n            return t.stringLiteral(stringList.map(s => this.stripQuotes(s.getText())).join(''));\n          } else if (number) {\n            const numText = number.getText();\n            const numValue = parseFloat(numText);\n            return t.numericLiteral(numValue);\n          } else {\n            return singleNodeReturn();\n          }\n        } else if (node instanceof CallArgumentsContext) {","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/cube-js/cube/blob/7d981676b36392fec34088b9afab6bdcad40207c/packages/cubejs-schema-compiler/src/parser/PythonParser.ts#L164-L200","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before (cubes.py)\nawait cube_config.load()\n// after\nload(cube_config)","handlingStrategy":"try-catch","validationCode":"// Guard degenerate trees by pre-parsing with error collection\nconst parser = new PythonParser(source);\nif (!parser.canParse()) throw new Error('Fix syntax errors before transpiling');","typeGuard":null,"tryCatchPattern":"try {\n  transpileToJs();\n} catch (e) {\n  if (e instanceof UserError && e.message.startsWith('Empty Python atom_expr node')) {\n    throw new Error(`Unsupported/empty expression in model: ${e.message}`);\n  }\n  throw e;\n}","preventionTips":["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"],"tags":["python","transpilation","schema-compiler","empty-node"],"backgroundTag":"python-transpile-unsupported-node","analyzedSha":"7d981676b36392fec34088b9afab6bdcad40207c","analyzedAt":"2026-09-02T03:45:10.400Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}