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.
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.