{"record":{"id":"95ffb22e9791ebe6","repo":"apache/superset","slug":"syntax-error","errorCode":"SYNTAX_ERROR","errorMessage":"SQL statement contains disallowed function(s): {functions}","messagePattern":"SQL statement contains disallowed function\\(s\\): (.+?)","errorType":"exception","errorClass":"SupersetDisallowedSQLFunctionException","httpStatus":500,"severity":"error","filePath":"superset/commands/sql_lab/estimate.py","lineNumber":112,"sourceCode":"    def _apply_sql_security(self, sql: str) -> str:\n        \"\"\"Run the disallowed-function/table, DML and RLS controls against the\n        SQL to be estimated, mirroring ``sql_lab.execute_sql_statements``.\n\n        Returns the SQL with RLS predicates injected (when ``RLS_IN_SQLLAB`` is\n        enabled), so the cost estimate reflects the same constrained query the\n        user would actually be allowed to run.\n        \"\"\"\n        db_engine_spec = self._database.db_engine_spec\n        parsed_script = SQLScript(sql, engine=db_engine_spec.engine)\n\n        disallowed_functions = app.config[\"DISALLOWED_SQL_FUNCTIONS\"].get(\n            db_engine_spec.engine,\n            set(),\n        )\n        if disallowed_functions and parsed_script.check_functions_present(\n            disallowed_functions\n        ):\n            raise SupersetDisallowedSQLFunctionException(disallowed_functions)\n\n        disallowed_tables = app.config[\"DISALLOWED_SQL_TABLES\"].get(\n            db_engine_spec.engine,\n            set(),\n        )\n        rls_enabled = is_feature_enabled(\"RLS_IN_SQLLAB\")\n\n        # Resolve the effective per-query schema once, the same way the execution\n        # path does (``sql_lab.execute_sql_statements``), but only when a control\n        # below actually needs it. Going through ``get_default_schema_for_query``\n        # rather than the static ``get_default_schema`` runs engine-specific\n        # per-query security gates too — e.g. ``PostgresEngineSpec`` rejects a\n        # query that sets ``search_path`` — and resolves unqualified references to\n        # the schema the engine uses at runtime, so both the denylist check and\n        # RLS injection match the execution path exactly.\n        catalog: str | None = None\n        effective_schema = \"\"\n        if disallowed_tables or rls_enabled:","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/apache/superset/blob/f4587218dd19d046c3e4d00063e7d27f8a2ed354/superset/commands/sql_lab/estimate.py#L94-L130","documentation":"Raised in the SQL preprocessing inside EstimateQueryCostCommand (superset/commands/sql_lab/estimate.py:112) as SupersetDisallowedSQLFunctionException when sqlscriptbox's SQLScript.check_functions_present() finds any function from the engine's DISALLOWED_SQL_FUNCTIONS config set in the submitted SQL. Cost estimation applies the same security controls as execution, so the estimator is intentionally blocked before reaching the database. Classified under SupersetErrorType.SYNTAX_ERROR.","triggerScenarios":"Estimating cost for SQL that calls a function listed in DISALLOWED_SQL_FUNCTIONS[engine] in superset_config.py — commonly things like sleep-like or filesystem functions; the denylist is engine-specific (keyed by db_engine_spec.engine).","commonSituations":"Operators add functions to DISALLOWED_SQL_FUNCTIONS to prevent DoS or data exfiltration, then users' previously estimable queries start failing; porting queries between engines with different denylists.","solutions":["Remove the disallowed function(s) from the SQL — the exception reports exactly which functions were found","Check superset_config.py DISALLOWED_SQL_FUNCTIONS for the engine in question to know what is banned","If the function is legitimately needed, ask the administrator to remove it from the denylist (an operator decision, not a code fix)"],"exampleFix":"-- before (DISALLOWED_SQL_FUNCTIONS contains pg_sleep for postgres)\nSELECT pg_sleep(10), * FROM accounts;\n\n-- after\nSELECT * FROM accounts;","handlingStrategy":"try-catch","validationCode":"# client-side pre-check: know the denylist for the engine\nDISALLOWED = {\"pg_sleep\", \"pg_read_file\"}  # mirror of DISALLOWED_SQL_FUNCTIONS['postgresql']\nused = extract_function_names(sql)\nviolations = used & DISALLOWED\nif violations:\n    raise ValueError(f\"remove disallowed functions: {sorted(violations)}\")","typeGuard":null,"tryCatchPattern":"try:\n    EstimateQueryCostCommand(params).run()\nexcept SupersetDisallowedSQLFunctionException as ex:\n    # ex lists the disallowed functions found; strip them from the SQL and retry","preventionTips":["Read DISALLOWED_SQL_FUNCTIONS from config documentation for your engine","The estimator enforces the same policy as execution — don't use it to 'test' banned SQL"],"tags":["sql-lab","security","sql-validation","query-cost","config"],"backgroundTag":null,"analyzedSha":"f4587218dd19d046c3e4d00063e7d27f8a2ed354","analyzedAt":"2026-08-14T22:39:27.425Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}