Manual error status handling
A Julia throw inside a --trim-compiled hand-written @ccallable does not become a Python exception — at best it aborts the host process. JuliaLibWrapping defines a convention for reporting errors across the C ABI so that generated wrappers can translate them into native exceptions.
An @api declaration generates this boundary automatically. This page is for authors designing an exact ABI by hand.
The JLWStatus convention
The canonical status struct is defined among the JLWInterop carriers subdir package and has the following shape:
struct JLWStatus
code::Int32 # 0 == success; non-zero == error
message::NTuple{256, UInt8} # UTF-8, null-terminated
endA library opts in by either
- returning a
JLWStatusdirectly, or - returning a struct that contains a
JLWStatusfield (any field name).
Either form is recognized by the Python backend.
The inline buffer keeps JLWStatus allocation-free and avoids pointer ownership concerns. Messages are bounded to 255 bytes plus a NUL terminator.
Authoring a library
Add JLWInterop to your library's project, then construct status values with the provided helpers:
using JLWInterop
struct ResultStruct
status::JLWStatus
value::Float64
end
Base.@ccallable function compute(x::Float64)::ResultStruct
x < 0 && return ResultStruct(jlw_error(1, "negative input"), 0.0)
return ResultStruct(jlw_ok(), x * 2)
endjlw_ok() and jlw_error(code, msg) perform no heap allocation, so they are safe in --trim builds.
What the Python wrapper does
For each entrypoint whose return type carries a JLWStatus (directly or via an embedded field), the generated wrapper checks status.code and raises a JLWError (a RuntimeError subclass, carrying .code and .message) when it is non-zero:
from mylib import compute, JLWError
try:
result = compute(-1.0)
except JLWError as e:
print(e.code, e.message) # 1, "negative input"On success the wrapper returns the full struct unchanged, including the status field (so callers can still inspect it explicitly if they prefer).
C backend
The C header generator does not currently auto-emit a status-check macro; C callers should check result.status.code themselves and read the message with, for example, printf("%.256s\n", result.status.message). A JLW_CHECK-style helper macro is a possible follow-up.