diesel-rs/diesel · error · syn::Error
expect `SQL` function blocks to be safe
Error message
expect `SQL` function blocks to be safe
What it means
Diesel's `sql_function!` foreign block must be safe; declaring it `unsafe extern "SQL"` is rejected in `parse`. SQL functions are not real FFI and never produce unsafe code, so the `unsafe` keyword is meaningless and disallowed.
Solutions
- Remove the `unsafe` keyword from the `extern "SQL"` block.
- Keep the block plain: `extern "SQL" { ... }`.
Example fix
// before
sql_function! {
unsafe extern "SQL" {
fn md5(x: Text) -> Text;
}
}
// after
sql_function! {
extern "SQL" {
fn md5(x: Text) -> Text;
}
} Defensive patterns
Strategy: validation
Validate before calling
// Reject unsafe in sql_function blocks before compiling:
// WRONG: unsafe extern "SQL" { ... }
// RIGHT: extern "SQL" { ... } Prevention
- Never write `unsafe` in diesel sql_function foreign blocks.
- When converting FFI extern blocks, remove both `unsafe` and the `C` ABI.
- Search your codebase for `unsafe extern "SQL"` before upgrading diesel versions.
When it happens
Trigger: Writing `unsafe extern "SQL" { ... }` inside `sql_function!` or `#[sql_function]` macro input.
Common situations: Copy-pasting an `unsafe extern "C"` FFI block and only changing the ABI string to `SQL`; assuming SQL function declarations need `unsafe` like normal externs.
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
- invalid variadic argument count: not enough function…
- cannot find argument corresponding to the generic
- expect `SQL` as ABI
- , the correct format is `#[aggregate]
- , the correct format is `#[skip_return_type_helper]
AI-assisted analysis of diesel-rs/diesel@6fa6ed01b2 (2026-09-07).
Data as JSON: /api/errors/c2213d37846fbe27.
Report an issue: GitHub.
Appendix: source
Thrown at diesel_derives/src/sql_function.rs:1180
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 {
match decl {
Ok(mut decl) => {
decl.attributes = merge_attributes(&parsed_block_attrs, decl.attributes);View on GitHub (pinned to 6fa6ed01b2)