prestodb/presto · error · PrestoException

FUNCTION_IMPLEMENTATION_ERROR

FUNCTION_IMPLEMENTATION_ERROR

Error message

Method %s does not return valid MethodHandle

What it means

When specializing a @ScalarFunction whose implementation method returns a MethodHandle (the codegen style used by built-in function parsers), Presto reflectively invokes the static method to obtain the handle. If the reflective invocation throws for any reason — wrong argument types, an exception inside the method, class-loading failure — the parser wraps it in FUNCTION_IMPLEMENTATION_ERROR saying the method did not return a valid MethodHandle. This is a plugin/function-authoring error, not a query-input error.

Source

Thrown at presto-main-base/src/main/java/com/facebook/presto/operator/scalar/annotations/CodegenScalarFromAnnotationsParser.java:147

                ImmutableList.of(),
                parseTypeSignature(method.getAnnotation(SqlType.class).value()),
                Arrays.stream(method.getParameters()).map(p -> parseTypeSignature(p.getAnnotation(SqlType.class).value())).collect(toImmutableList()),
                false);

        ComplexTypeFunctionDescriptor descriptor = parseAndCheckFunctionDescriptor(method, signature);

        return new SqlScalarFunction(signature)
        {
            @Override
            public BuiltInScalarFunctionImplementation specialize(BoundVariables boundVariables, int arity, FunctionAndTypeManager functionAndTypeManager)
            {
                Signature boundSignature = applyBoundVariables(signature, boundVariables, arity);
                MethodHandle handle;
                try {
                    handle = (MethodHandle) method.invoke(null, boundSignature.getArgumentTypes().stream().map(t -> functionAndTypeManager.getType(t)).toArray());
                }
                catch (Exception e) {
                    throw new PrestoException(FUNCTION_IMPLEMENTATION_ERROR, format("Method %s does not return valid MethodHandle", method), e);
                }
                return new BuiltInScalarFunctionImplementation(
                        method.getAnnotation(SqlNullable.class) != null,
                        getArgumentProperties(method),
                        handle,
                        Optional.empty());
            }

            @Override
            public SqlFunctionVisibility getVisibility()
            {
                return codegenScalarFunction.visibility();
            }

            @Override
            public boolean isDeterministic()
            {
                return codegenScalarFunction.deterministic();

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Check the plugin/server log for the cause chain (the PrestoException carries the original exception).
  2. Verify the static method signature matches the declared argument types and arity exactly.
  3. Confirm the method is public, static, and returns java.lang.invoke.MethodHandle.
  4. Rebuild the plugin against the exact Presto version in use to fix API drift.
  5. Test function registration in isolation (a minimal plugin) to pinpoint the failing method.

Example fix

// before (mismatched arity)
public static MethodHandle lessThan(Type type) { ... }
// after
public static MethodHandle lessThan(Type leftType, Type rightType) { ... }
Defensive patterns

Strategy: try-catch

Type guard

// pre-check before registering
Class<?> c = method.getReturnType();
boolean valid = java.lang.reflect.Modifier.isStatic(method.getModifiers())
    && MethodHandle.class.isAssignableFrom(c);

Try / catch

try { registry.registerFunctions(ScalarFunction.class, classLoader); } catch (PrestoException e) { if (e.getErrorCode().getName().equals("FUNCTION_IMPLEMENTATION_ERROR")) { log.error("Bad MethodHandle function: " + e.getCause(), e); throw e; } }

Prevention

When it happens

Trigger: Registering a scalar function whose generate-* static method has a signature mismatch with the declared @TypeParameter/@SqlType annotations, throws internally, or cannot be invoked with the resolved Type array (e.g. wrong arity or incompatible types).

Common situations: Custom connector/function plugin development; upgrading Presto where the MethodHandle-based function API changed; typos in @TypeParameter names so bound types don't match the method parameters.

Related errors


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/d45749a8b561810b. Report an issue: GitHub.