Diagnostics¶
The SDK emits warnings through the standard log::warn! macro
whenever something in the plugin lifecycle goes wrong silently. Every
message is prefixed with [rust-samp] so it can be grepped quickly in
the server log:
The prefix is a single constant in samp/src/macros.rs
(SDK_LOG_PREFIX) — do not hardcode the literal in your own logs.
Where they fire¶
These warnings cover the native Open Multiplayer lifecycle; on SA-MP the SDK does not emit any of them (the corresponding failure modes do not exist in that environment).
| Trigger | Message | Consequence |
|---|---|---|
ICore* was null in comp_on_load |
null ICore* in on_load — samp::plugin::omp_core() will return None |
Plugin keeps running; omp_core() returns None. |
IPawnComponent missing in comp_on_init |
IPawnComponent not found in on_init — Pawn natives unavailable |
Native registration is skipped; Pawn cannot call your natives. |
IEventDispatcher<PawnEventHandler> null in comp_on_init |
null IEventDispatcher<PawnEventHandler> in on_init — on_amx_load/on_amx_unload will not be called |
Loaded Pawn scripts do not trigger the AMX hooks. |
getAmxFunctions() returned 0 even at on_ready |
getAmxFunctions() returned 0 in on_ready — Pawn natives unavailable |
Pawn natives are not registered, even after the deferred retry. |
on_ready: IPawnComponent could not be queried again |
on_ready: IPawnComponent not found |
Same as the previous row — natives are not registered. |
ITimersComponent missing while enable_tick() is on |
ITimersComponent not found — on_tick will not be called |
Tick callback never fires on Open Multiplayer (SA-MP unaffected). |
ITimersComponent::create() returned null |
failed to create timer on ITimersComponent — on_tick will not be called |
Same as above; the heap handler is freed before the warning is emitted. |
Panic safety¶
Beyond the warnings, the SDK wraps every callback that crosses the
FFI boundary in std::panic::catch_unwind. If a panic escapes the
plugin code:
- Inside a native — the
#[native]wrapper catches the panic, logs[<NativeName>] panic in native: <payload>throughsamp::log::error!, and returns0to the AMX VM. - Inside an Open Multiplayer vtable callback (
comp_on_load,comp_on_init,comp_on_ready,comp_on_free,comp_free,pawn_on_amx_load,pawn_on_amx_unload,tick_handler_timeout,tick_handler_free) — the SDK catches the panic so the server process is not aborted.
Without those guards a panic crossing extern "C" aborts the entire
server (Rust 1.71+ guarantee).
Native-call error logging¶
When a native is declared with a Result/AmxResult return, the
generated wrapper logs Err automatically:
For argument parsing failures the wrapper logs a more detailed message that includes the positional index and the expected type:
This kicks in only in the standard #[native] mode. In raw mode
the macro hands the Args over verbatim and parsing is the plugin's
responsibility.
Reporting the SDK version¶
samp::version() returns the CARGO_PKG_VERSION of the rust-samp
crate the plugin was built against. Surface it through a Pawn native so
bug reports and diagnostic dashboards carry the exact SDK build:
#[native(name = "MyPlugin_GetSdkVersion")]
fn get_sdk_version(_amx: &Amx, out: &mut UnsizedBuffer, size: usize) -> bool {
let buf = out.into_sized_buffer(size);
buf.write_str(samp::version()).is_ok()
}
Reading the warnings¶
All messages flow through whatever log implementation the plugin
installed. With the default routing they end up wherever the server
sends logprintf (SA-MP) or ICore::logLnU8 (Open Multiplayer).
With a custom fern::Dispatch they follow the dispatch chain
described in Logging.
A practical filter in the server console:
Where to look next when something is wrong¶
omp_core()returnsNonedespite running on Open Multiplayer → check the first warning above. The server may have passed a nullICore*, or the plugin is in legacy mode (noComponentEntryPoint).- A Pawn
native MyNative(...)is reported as unresolved by the script compiler at runtime → check theIPawnComponent/getAmxFunctionswarnings. The dispatcher might not have firedon_amx_loadfor this script either. on_amx_loadis never called → look for theIEventDispatcher<PawnEventHandler>warning.on_tickis never called on Open Multiplayer → look for theITimersComponentwarnings. Make suresamp::plugin::enable_tick()is called inside the constructor block.