{"record":{"id":"4a79e3266aaac568","repo":"iflytek/astron-agent","slug":"pg-sql-node-execution-error-database-dml-statement","errorCode":"PG_SQL_NODE_EXECUTION_ERROR","errorMessage":"Database DML statement generation failed: {err}","messagePattern":"Database DML statement generation failed: (.+?)","errorType":"error_code","errorClass":"CustomException","httpStatus":null,"severity":"error","filePath":"core/workflow/engine/nodes/pgsql/pgsql_node.py","lineNumber":491,"sourceCode":"                    ),\n                }.get(\n                    self.mode,\n                    lambda: (_ for _ in ()).throw(  # Throw exception for invalid mode\n                        CustomException(\n                            err_code=CodeEnum.PG_SQL_PARAM_ERROR,\n                            err_msg=\"Mode is out of range\",\n                            cause_error=\"Mode is out of range\",\n                        )\n                    ),\n                )()\n                # Log generated SQL for tracing\n                await request_span.add_info_events_async({\"sql_string\": compiled_sql})\n                return compiled_sql\n            except Exception as e:\n                # Handle any errors during SQL generation\n                err = str(e)\n                request_span.add_error_event(err)\n                raise CustomException(\n                    err_code=CodeEnum.PG_SQL_NODE_EXECUTION_ERROR,\n                    err_msg=f\"Database DML statement generation failed: {err}\",\n                    cause_error=f\"Database DML statement generation failed: {err}\",\n                ) from e\n\n    async def generate_config(\n        self,\n        inputs: dict,\n        is_release: bool,\n        span: Span,\n    ) -> PGSqlConfig:\n        \"\"\"Generate PostgreSQL configuration for database operations.\n\n        :param inputs: Input data dictionary containing variable values\n        :param is_release: Whether this is a production release\n        :param span: Tracing span for monitoring\n        :return: Configured PGSqlConfig object\n        :raises CustomException: If required parameters are missing","sourceCodeStart":473,"sourceCodeEnd":509,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/core/workflow/engine/nodes/pgsql/pgsql_node.py#L473-L509","documentation":"Catch-all wrapper in `generate_dml`: any exception during SQL generation/validation/compilation (SQLAlchemy compile errors, bad identifiers, template/variable resolution failures, plus the PG_SQL_PARAM_ERROR sub-cases) is re-raised as PG_SQL_NODE_EXECUTION_ERROR with the original message embedded.","triggerScenarios":"Calling `generate_dml` (via `generate_config`) when SQLAlchemy's `text(...).bindparams(...).compile(...)` fails — invalid table/column identifiers, type-unresolvable literal binds, malformed mode/case data, or an unknown DBMode.","commonSituations":"Table or column names contain characters needing quoting; case values are of types SQLAlchemy cannot literal-bind (dict, bytes); mode enum mismatch after config schema changes; custom SQL with bad placeholders.","solutions":["Read the inner `{err}` text to find which statement failed and why.","Print/inspect the compiled SQL by running generate_dml locally with the same node config.","Validate table/column identifiers and case value types (str/int/float/bool only) in the node config.","If the inner error is 'WHERE condition is empty', fix the cases as in errors 1326/1327; if it's a compile error, fix the SQL/identifiers."],"exampleFix":"// before\ncases=[Case(column=\"created_at\", operator=\">\", value={\"nested\": \"dict\"})]  # cannot literal-bind\n// after\ncases=[Case(column=\"created_at\", operator=\">\", value=\"2024-01-01 00:00:00\")]","handlingStrategy":"try-catch","validationCode":"# pre-validate identifiers and bindable types\ndef check_dml_inputs(cfg) -> str | None:\n    if cfg.tableName and not cfg.tableName.replace(\"_\", \"\").isalnum():\n        return f\"Invalid table name: {cfg.tableName}\"\n    for c in getattr(cfg, \"cases\", []) or []:\n        if not isinstance(c.value, (str, int, float, bool)):\n            return f\"Non-bindable case value type: {type(c.value)}\"\n    return None","typeGuard":null,"tryCatchPattern":"try:\n    sql = await node.generate_dml(span)\nexcept CustomException as e:\n    log.error(\"DML generation failed\", detail=str(e))  # inner err names the real cause\n    raise","preventionTips":["Keep case values limited to str/int/float/bool so SQLAlchemy can literal-bind","Use quoted-safe, conventional identifiers for tables and columns","Dry-run SQL generation in the node debugger before publishing the workflow"],"tags":["sql","sqlalchemy","dml","statement-generation"],"backgroundTag":"sql-query-failed","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-19T12:17:13.211Z"}