{"record":{"id":"571c49d24c7963d6","repo":"prestodb/presto","slug":"query-planning-timeout","errorCode":"QUERY_PLANNING_TIMEOUT","errorMessage":"The query optimizer exceeded the timeout of %s.","messagePattern":"The query optimizer exceeded the timeout of (.+?)\\.","errorType":"error_code","errorClass":"PrestoException","httpStatus":null,"severity":"error","filePath":"presto-main-base/src/main/java/com/facebook/presto/sql/Optimizer.java","lineNumber":111,"sourceCode":"        this.planChecker = requireNonNull(planChecker, \"planChecker is null\");\n        this.metadata = requireNonNull(metadata, \"metadata is null\");\n        this.variableAllocator = requireNonNull(variableAllocator, \"variableAllocator is null\");\n        this.idAllocator = requireNonNull(idAllocator, \"idAllocator is null\");\n        this.warningCollector = requireNonNull(warningCollector, \"warningCollector is null\");\n        this.statsCalculator = requireNonNull(statsCalculator, \"statsCalculator is null\");\n        this.costCalculator = requireNonNull(costCalculator, \"costCalculator is null\");\n        this.explain = explain;\n    }\n\n    public Plan validateAndOptimizePlan(PlanNode root, PlanStage stage)\n    {\n        validateIntermediatePlanWithRuntimeStats(root);\n\n        boolean enableVerboseRuntimeStats = SystemSessionProperties.isVerboseRuntimeStatsEnabled(session) || SystemSessionProperties.isVerbosePlannerRuntimeStatsEnabled(session);\n        if (stage.ordinal() >= OPTIMIZED.ordinal()) {\n            for (PlanOptimizer optimizer : planOptimizers) {\n                if (Thread.currentThread().isInterrupted()) {\n                    throw new PrestoException(QUERY_PLANNING_TIMEOUT, String.format(\"The query optimizer exceeded the timeout of %s.\", getQueryAnalyzerTimeout(session).toString()));\n                }\n                long start = System.nanoTime();\n                PlanOptimizerResult optimizerResult = optimizer.optimize(root, session, TypeProvider.viewOf(variableAllocator.getVariables()), variableAllocator, idAllocator, warningCollector);\n                requireNonNull(optimizerResult, format(\"%s returned a null plan\", optimizer.getClass().getName()));\n                if (enableVerboseRuntimeStats || trackOptimizerRuntime(session, optimizer)) {\n                    session.getRuntimeStats().addMetricValue(String.format(\"optimizer%sTimeNanos\", getOptimizerNameForLog(optimizer)), NANO, System.nanoTime() - start);\n                }\n                TypeProvider types = TypeProvider.viewOf(variableAllocator.getVariables());\n\n                collectOptimizerInformation(optimizer, root, optimizerResult, types);\n                root = optimizerResult.getPlanNode();\n            }\n        }\n        if (stage.ordinal() >= OPTIMIZED_AND_VALIDATED.ordinal()) {\n            // make sure we produce a valid plan after optimizations run. This is mainly to catch programming errors\n            validateFinalPlanWithRuntimeStats(root);\n        }\n","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-main-base/src/main/java/com/facebook/presto/sql/Optimizer.java#L93-L129","documentation":"Thrown by Optimizer.validateAndOptimizePlan when the current thread is interrupted between running plan optimizers, indicating the query planning phase exceeded its allowed time (query.analyzer-timeout / planning timeout). Presto interrupts the planning thread once the deadline passes, and the optimizer loop converts the interrupt into a QUERY_PLANNING_TIMEOUT failure.","triggerScenarios":"A query whose logical/optimized plan takes longer than the analyzer timeout: running an optimizer detects Thread.currentThread().isInterrupted() and throws. Triggered via plan/getLogicalPlan/createPlan on very large or pathological queries with expensive optimizer passes.","commonSituations":"Huge SQL with thousands of joins/unions; queries over thousands of columns; low query.analyzer-timeout session setting; cluster under CPU starvation slowing planning.","solutions":["Increase the query.analyzer-timeout (planning timeout) session or config property","Simplify the query (reduce join/union fan-out, split into stages) so planning completes in time","Check cluster CPU load; planning is CPU-bound and contention lengthens it","Profile which optimizer pass is slow (verbose planner runtime stats) and disable/avoid the pattern that triggers it"],"exampleFix":"// before\nSET SESSION query_analyzer_timeout = '2m';\n// after\nSET SESSION query_analyzer_timeout = '10m';","handlingStrategy":"try-catch","validationCode":"Duration timeout = getQueryAnalyzerTimeout(session);\n// estimate planning cost before submitting: column/join count heuristics\nif (joinCount > 50 || columnCount > 1000) { /* warn or raise timeout */ }","typeGuard":null,"tryCatchPattern":"try { Plan p = planner.plan(...); } catch (PrestoException e) { if (e.getErrorCode() == QUERY_PLANNING_TIMEOUT.toErrorCode()) { /* increase timeout, simplify query, or resubmit */ } else throw e; }","preventionTips":["Set query.analyzer-timeout generously for large analytical queries","Avoid thousand-way joins/unions; split queries into staged materializations","Monitor optimizer runtime stats to find slow passes","Keep cluster CPU headroom; planning is CPU-bound"],"tags":["planning","timeout","optimizer","presto"],"backgroundTag":"query-planning-timeout","analyzedSha":"55bb57d202de3b926896fa966c2c4a44c779634e","analyzedAt":"2026-09-04T12:50:26.162Z","contentChangedAt":"2026-09-04T12:50:26.162Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}