diesel-rs/diesel · error · syn::Error

expect `SQL` as ABI

Error message

expect `SQL` as ABI

What it means

The `sql_function!` macro parses an `extern "SQL" { ... }` block. The ABI string of the foreign module must be exactly `"SQL"`; any other ABI (e.g. `"C"`, missing name, or a typo) is rejected in `parse` with this error.

Solutions

  1. Change the ABI to exactly `extern "SQL"`.
  2. If you omitted the ABI string, add `"SQL"` after `extern`.
  3. Check for case mistakes: it must be uppercase `SQL`.

Example fix

// before
sql_function! {
    extern "C" {
        fn lower(x: Text) -> Text;
    }
}

// after
sql_function! {
    extern "SQL" {
        fn lower(x: Text) -> Text;
    }
}
Defensive patterns

Strategy: validation

Validate before calling

// Use the canonical template for sql_function blocks:
// sql_function! { extern "SQL" { fn name(args...) -> Ret; } }

Prevention

When it happens

Trigger: Writing `extern "C" { ... }`, `extern { ... }`, or misspelled ABI (e.g. `extern "sql"`) inside a `sql_function!` invocation or a module using the `#[sql_function]` foreign-mod syntax.

Common situations: Copy-pasting a normal FFI extern block into `sql_function!`; IDE auto-completing `extern "C"`; case-sensitivity mistakes (`"sql"` vs `"SQL"`).

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of diesel-rs/diesel@6fa6ed01b2 (2026-09-07). Data as JSON: /api/errors/fa8916c55d7054a7. Report an issue: GitHub.

Appendix: source

Thrown at diesel_derives/src/sql_function.rs:1177

impl Parse for ExternSqlBlock {
    fn parse(input: ParseStream) -> Result<Self> {
        let mut error = None::<syn::Error>;

        let mut combine_error = |e: syn::Error| {
            error = Some(
                error
                    .take()
                    .map(|mut o| {
                        o.combine(e.clone());
                        o
                    })
                    .unwrap_or(e),
            )
        };

        let block = syn::ItemForeignMod::parse(input)?;
        if block.abi.name.as_ref().map(|n| n.value()) != Some("SQL".into()) {
            return Err(syn::Error::new(block.abi.span(), "expect `SQL` as ABI"));
        }
        if let Some(unsafety) = block.unsafety {
            return Err(syn::Error::new(
                unsafety.span(),
                "expect `SQL` function blocks to be safe",
            ));
        }

        let parsed_block_attrs = parse_attributes(&mut combine_error, block.attrs);

        let item_count = block.items.len();
        let function_decls_input = block
            .items
            .into_iter()
            .map(|i| syn::parse2::<SqlFunctionDecl>(quote! { #i }));

        let mut function_decls = Vec::with_capacity(item_count);
        for decl in function_decls_input {

View on GitHub (pinned to 6fa6ed01b2)