{"record":{"id":"6cb46af6e4ca55f9","repo":"prestodb/presto","slug":"must-be-window-function","errorCode":"MUST_BE_WINDOW_FUNCTION","errorMessage":"Not a window function: %s","messagePattern":"Not a window function: (.+?)","errorType":"error_code","errorClass":"SemanticException","httpStatus":null,"severity":"error","filePath":"presto-main-base/src/main/java/com/facebook/presto/sql/analyzer/StatementAnalyzer.java","lineNumber":4198,"sourceCode":"                List<FunctionCall> nestedWindowFunctions = extractWindowFunctions(toExtract.build());\n\n                if (!nestedWindowFunctions.isEmpty()) {\n                    throw new SemanticException(NESTED_WINDOW, node, \"Cannot nest window functions inside window function '%s': %s\",\n                            windowFunction,\n                            windowFunctions);\n                }\n\n                if (windowFunction.isDistinct()) {\n                    throw new SemanticException(NOT_SUPPORTED, node, \"DISTINCT in window function parameters not yet supported: %s\", windowFunction);\n                }\n\n                if (window.getFrame().isPresent()) {\n                    analyzeWindowFrame(window.getFrame().get());\n                }\n\n                FunctionKind kind = functionAndTypeResolver.getFunctionMetadata(analysis.getFunctionHandle(windowFunction)).getFunctionKind();\n                if (kind != AGGREGATE && kind != WINDOW) {\n                    throw new SemanticException(MUST_BE_WINDOW_FUNCTION, node, \"Not a window function: %s\", windowFunction.getName());\n                }\n            }\n\n            return windowFunctions;\n        }\n\n        private void analyzeWindowFrame(WindowFrame frame)\n        {\n            FrameBound.Type startType = frame.getStart().getType();\n            FrameBound.Type endType = frame.getEnd().orElseGet(() -> new FrameBound(CURRENT_ROW)).getType();\n\n            if (startType == UNBOUNDED_FOLLOWING) {\n                throw new SemanticException(INVALID_WINDOW_FRAME, frame, \"Window frame start cannot be UNBOUNDED FOLLOWING\");\n            }\n            if (endType == UNBOUNDED_PRECEDING) {\n                throw new SemanticException(INVALID_WINDOW_FRAME, frame, \"Window frame end cannot be UNBOUNDED PRECEDING\");\n            }\n            if ((startType == CURRENT_ROW) && (endType == PRECEDING)) {","sourceCodeStart":4180,"sourceCodeEnd":4216,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-main-base/src/main/java/com/facebook/presto/sql/analyzer/StatementAnalyzer.java#L4180-L4216","documentation":"Every function used with an OVER clause must be either an AGGREGATE or a WINDOW kind function. After resolving the function handle, the analyzer checks the FunctionKind metadata; if it is neither (e.g. a scalar function), this MUST_BE_WINDOW_FUNCTION error is thrown. It usually means OVER was attached to a function that can't be windowed.","triggerScenarios":"`SELECT abs(x) OVER (PARTITION BY y) FROM t` or any scalar/rank-like misuse — getFunctionKind(analysis.getFunctionHandle(windowFunction)) returns something other than AGGREGATE or WINDOW.","commonSituations":"Typos in window function names falling back to a scalar function of similar name (e.g. `rank()` misspelled); applying OVER to scalar helpers like concat/abs; custom SQL functions registered as SCALAR being used in analytic contexts; engine migrations where a UDF exists as scalar in Presto but as window function elsewhere.","solutions":["Check the function name spelling and use a supported window function (row_number, rank, dense_rank, lag, lead, etc.).","Remove the OVER clause if the function is scalar and windowing is not actually needed.","Verify with `SHOW FUNCTIONS` that the intended function is of kind aggregate or window.","If a custom function is needed as a window function, implement/register it with WINDOW (or AGGREGATE) kind instead of SCALAR."],"exampleFix":"-- before\nSELECT abs(x) OVER (PARTITION BY y) FROM t;\n-- after\nSELECT abs(x) FROM t; -- or use a real window function:\nSELECT row_number() OVER (PARTITION BY y ORDER BY x) FROM t;","handlingStrategy":"validation","validationCode":"-- Confirm the function is window-capable before attaching OVER:\nSELECT function_name, function_kind FROM information_schema.functions WHERE function_name = 'your_fn';\n-- only proceed if function_kind IN ('aggregate', 'window').","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run SHOW FUNCTIONS / query information_schema.functions to verify function kind before using OVER.","Attach OVER only to known window functions or aggregates.","Verify custom UDFs are registered with the right kind (WINDOW/AGGREGATE, not SCALAR) for analytic use.","Watch for spellcheck-adjacent typos: a mistyped window function name may resolve to a scalar function."],"tags":["sql","window-function","function-kind","semantic-analysis"],"backgroundTag":"not-a-window-function","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"}