Skip to content

Conversation

@Jefffrey
Copy link
Contributor

@Jefffrey Jefffrey commented Jan 30, 2026

Which issue does this PR close?

Rationale for this change

Current error message for calling functions with incorrect arguments isn't very user friendly. Some examples:

> select log('');
Error during planning: Internal error: Function 'log' failed to match any signature, errors: Error during planning: Function 'log' requires TypeSignatureClass::Decimal, but received String (DataType: Utf8).,Error during planning: Function 'log' requires TypeSignatureClass::Float, but received String (DataType: Utf8).,Error during planning: Function 'log' expects 2 arguments but received 1,Error during planning: Function 'log' expects 2 arguments but received 1.
This issue was likely caused by a bug in DataFusion's code. Please help us to resolve this by filing a bug report in our issue tracker: https://github.com/apache/datafusion/issues No function matches the given name and argument types 'log(Utf8)'. You might need to add explicit type casts.
        Candidate functions:
        log(Coercion(TypeSignatureClass::Decimal))
        log(Coercion(TypeSignatureClass::Float, implicit_coercion=ImplicitCoercion([Numeric], default_type=Float64))
        log(Coercion(TypeSignatureClass::Float, implicit_coercion=ImplicitCoercion([Numeric], default_type=Float64), Coercion(TypeSignatureClass::Decimal))
        log(Coercion(TypeSignatureClass::Float, implicit_coercion=ImplicitCoercion([Numeric], default_type=Float64), Coercion(TypeSignatureClass::Float, implicit_coercion=ImplicitCoercion([Numeric], default_type=Float64))
> select abs('');
Error during planning: Function 'abs' expects NativeType::Numeric but received NativeType::String No function matches the given name and argument types 'abs(Utf8)'. You might need to add explicit type casts.
        Candidate functions:
        abs(Numeric(1))
> select make_array([]);
+--------------------------+
| make_array(make_array()) |
+--------------------------+
| [[]]                     |
+--------------------------+
1 row(s) fetched.
Elapsed 0.051 seconds.
> select greatest();
Error during planning: Execution error: Function 'greatest' user-defined coercion failed with "Error during planning: greatest was called without any arguments. It requires at least 1." No function matches the given name and argument types 'greatest()'. You might need to add explicit type casts.
        Candidate functions:
        greatest(UserDefined)
  • There's quite some word spam, especially for the log case; it stems from using a OneOf signature, and we currently concatenate each error from each signature inside the OneOf resulting in a large error message that isn't very helpful
  • Some error messages are direct about whats wrong, such as abs, which is nice
  • User defined signatures still display Candidate functions which isn't very helpful (greatest(UserDefined) doesn't really help the user understand the available signatures since user defined is opaque)

Contrast this with DuckDB:

D select log([]);
Binder Error:
No function matches the given name and argument types 'log("NULL"[])'. You might need to add explicit type casts.
        Candidate functions:
        log(DOUBLE) -> DOUBLE
        log(DOUBLE, DOUBLE) -> DOUBLE


LINE 1: select log([]);

Or Postgres:

postgres=# select sha256(1, 1);
ERROR:  function sha256(integer, integer) does not exist
LINE 1: select sha256(1, 1);
               ^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.

It looks like they prefer to omit stating specific errors, and only give general advice; for DuckDB they list the available call types, for Postgres they omit this and leave it a simple error with only details on how it was called.

This PR looks into removing some of the word spam from error messages and tries to make them more consistent with each other.

What changes are included in this PR?

When a function call fails because no signatures match, the displayed error either:

  • For user-defined signatures, it will simply pass on the error from the coerce_types call of the UDF (we omit candidate functions message)
  • For other signatures, we strip away the specific error message and display only the candidate functions

For example, user-defined:

> select greatest();
Error during planning: User-defined coercion of function call 'greatest()' failed with:
greatest was called without any arguments. It requires at least 1.

For all other signatures:

> select log([]);
Error during planning: Failed to coerce function call 'log(List(Null))'. You might need to add explicit type casts.
        Candidate functions:
        log(Coercion(TypeSignatureClass::Decimal))
        log(Coercion(TypeSignatureClass::Float, implicit_coercion=ImplicitCoercion([Numeric], default_type=Float64))
        log(Coercion(TypeSignatureClass::Float, implicit_coercion=ImplicitCoercion([Numeric], default_type=Float64), Coercion(TypeSignatureClass::Decimal))
        log(Coercion(TypeSignatureClass::Float, implicit_coercion=ImplicitCoercion([Numeric], default_type=Float64), Coercion(TypeSignatureClass::Float, implicit_coercion=ImplicitCoercion([Numeric], default_type=Float64))
> select abs('');
Error during planning: Failed to coerce function call 'abs(Utf8)'. You might need to add explicit type casts.
        Candidate functions:
        abs(Numeric(1))

Although it means we don't show a specific error anymore (see how abs no longer specifies it was because it received string instead of a numeric), I think this is an easier way to manage signature errors to be consistent for functions that have a single signature and those that are OneOf types. It also aligns with DuckDB.

Are these changes tested?

Yes.

Are there any user-facing changes?

Yes, error messages for failed function calls changes.

@github-actions github-actions bot added sql SQL Planner logical-expr Logical plan and expressions optimizer Optimizer rules sqllogictest SQL Logic Tests (.slt) labels Jan 30, 2026
@Jefffrey
Copy link
Contributor Author

If we decide to go this route, there is still some followup work:

  • Improve display of coercible API (e.g. the candidate functions of log isn't very user friendly)
  • Look into cleaning up error messages from type_coercion/functions.rs given we strip away most of them (all except user defined) for simplicity
  • Look into making array signatures consistent

For example this is how array function errors look like:

> select array_extract(1,2,3);
Error during planning: Failed to coerce function call 'array_element(Int64, Int64, Int64)'. You might need to add explicit type casts.
        Candidate functions:
        array_element(array, index)
  • Ideally we'd show specific types instead of just index; though this is more about ensuring all the signatures have a consistent way of displaying themselves

@Jefffrey Jefffrey marked this pull request as ready for review January 30, 2026 05:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

logical-expr Logical plan and expressions optimizer Optimizer rules sql SQL Planner sqllogictest SQL Logic Tests (.slt)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant