{"record":{"id":"5c40e706ccee4cb9","repo":"prestodb/presto","slug":"function-implementation-error-5c40e7","errorCode":"FUNCTION_IMPLEMENTATION_ERROR","errorMessage":"When function got no input, it should either produce output or return Blocked state","messagePattern":"When function got no input, it should either produce output or return Blocked state","errorType":"error_code","errorClass":"PrestoException","httpStatus":null,"severity":"error","filePath":"presto-main-base/src/main/java/com/facebook/presto/operator/RegularTableFunctionPartition.java","lineNumber":139,"sourceCode":"            public WorkProcessor.ProcessState<Page> process()\n            {\n                TableFunctionProcessorState state = tableFunction.process(inputPages);\n                boolean functionGotNoData = inputPages == null;\n                if (state == FINISHED) {\n                    return WorkProcessor.ProcessState.finished();\n                }\n                if (state instanceof TableFunctionProcessorState.Blocked) {\n                    return WorkProcessor.ProcessState.blocked(toListenableFuture(((TableFunctionProcessorState.Blocked) state).getFuture()));\n                }\n                TableFunctionProcessorState.Processed processed = (TableFunctionProcessorState.Processed) state;\n                if (processed.isUsedInput()) {\n                    inputPages = prepareInputPages();\n                }\n                if (processed.getResult() != null) {\n                    return WorkProcessor.ProcessState.ofResult(appendPassThroughColumns(processed.getResult()));\n                }\n                if (functionGotNoData) {\n                    throw new PrestoException(FUNCTION_IMPLEMENTATION_ERROR, \"When function got no input, it should either produce output or return Blocked state\");\n                }\n                return WorkProcessor.ProcessState.blocked(immediateFuture(null));\n            }\n        });\n    }\n\n    /**\n     * Iterate over the partition by page and extract pages for each table function source from the input page.\n     * For each source, project the columns required by the table function.\n     * If for some source all data in the partition has been consumed, Optional.empty() is returned for that source.\n     * It happens when the partition of this source is shorter than the partition of some other source.\n     * The overall length of the table function partition is equal to the length of the longest source partition.\n     * When all sources are fully consumed, this method returns null.\n     * <p>\n     * NOTE: There are two types of table function's source semantics: set and row. The two types of sources should be handled\n     * by the TableFunctionDataProcessor in different ways. For a source with set semantics, the whole partition can be used for computations,\n     * while for a source with row semantics, each row should be processed independently from all other rows.\n     * To enforce that behavior, we could pass to the TableFunctionDataProcessor only one row from a table with row semantics.","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-main-base/src/main/java/com/facebook/presto/operator/RegularTableFunctionPartition.java#L121-L157","documentation":"FUNCTION_IMPLEMENTATION_ERROR raised by RegularTableFunctionPartition.process when a table function implementation neither produced an output page nor declared itself Blocked despite receiving no input data in this round. Table functions follow a WorkProcessor protocol: each step must yield a result, be blocked, or have consumed input; producing neither violates the contract. This is a bug in the table function's implementation, not user SQL.","triggerScenarios":"The function's processor (TableFunctionProcessorState) reports processed data but getResult() is null and functionGotNoData is true — i.e. the processor neither returned a page nor a blocked continuation while no input rows were supplied.","commonSituations":"Developing a custom TableFunctionDataProcessor that returns finished/processed states inconsistently; changing partitioning or pass-through semantics so the function is invoked with empty partitions; upgrading Presto where the processor state contract became stricter.","solutions":["Fix the table function implementation so that when no input is present it either produces a result page or returns a blocked state.","Check the processor's contract handling of empty input partitions (set vs rows source semantics).","If using a built-in function, reproduce with a minimal query and file a bug with the function name and plan.","Verify the state machine transitions in processOperator/processed handling conform to WorkProcessor.ProcessState expectations."],"exampleFix":"// before (custom table function)\nif (state.isFinished()) { return ProcessState.finished(); }\n// never yields result or blocked on empty input\n// after\nif (state.isFinished()) { return ProcessState.finished(); }\nif (noInputProcessed && state.getResult() == null) {\n    return ProcessState.blocked(immediateFuture(null));\n}","handlingStrategy":"try-catch","validationCode":"// When authoring a table function, unit-test the empty-input path:\n@Test\nvoid emptyPartitionMustBlockOrEmit() {\n    var state = processor.process(emptyInput);\n    assertTrue(state.getResult() != null || state.isBlocked(),\n        \"function with no input must produce output or be blocked\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    functionOutput = executeTableFunctionQuery();\n} catch (PrestoException e) {\n    if (\"FUNCTION_IMPLEMENTATION_ERROR\".equals(e.getErrorCode().getName())\n            && e.getMessage().contains(\"no input\")) {\n        throw new IllegalStateException(\"table function bug; report to function author\", e);\n    }\n    throw e;\n}","preventionTips":["Test custom table functions with empty partitions and single-row inputs","Follow the WorkProcessor state contract strictly: result, blocked, or finished each step","Keep processor state-machine handling up to date when upgrading Presto","Report built-in function hits upstream with a minimal repro"],"tags":["table-function","work-processor","plugin-bug"],"backgroundTag":"table-function-contract-violation","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"}