Falcon telemetry
Instrument Falcon Solana submissions so acceptance and landing stay separate metrics, per transport, without ever logging your API key.
Falcon's response tells you almost nothing about whether a transaction landed, and each transport tells you a different amount. So instrument for that: one record for what Falcon said, one record for what the chain did, joined on the signature.
What to measure
Since no HTTP route reports a forwarding failure, a 200 rate near 100% is the expected steady state rather than a health signal. The number that means something is your landing rate, measured on your Solana RPC.
| Metric | Source | What a drop means |
|---|---|---|
| Acceptance rate | Falcon response per transport | Your requests are malformed, unauthorized or over the allowance |
| Landing rate | getSignatureStatuses on your RPC | Competition, tip level, blockhash expiry, or delivery loss |
| Time to first observation | Submit timestamp → first status | Regional or pacing problems |
| Expiry rate | Signatures that never landed before blockhash expiry | You are retrying past the useful window |
Track them separately per transport and per region, or you'll average away the one transport that's failing.
What each transport can tell you
| Transport | Record | Structurally unavailable |
|---|---|---|
| JSON-RPC | HTTP status, JSON-RPC code, message prefix, data.minimumLamports / data.expected / data.actual | Forwarding outcome |
/binary, /plaintext | HTTP status and the plain-text body | Forwarding outcome; the body is the only way to separate two different 413s or seven different 400s |
| QUIC | Whether the error was a SubmitError or a transport error, the variant, and the active TransportMode | Forwarding outcome; in datagram mode, acceptance too |
| Native UDP | Local send() errors only | Everything else: acceptance, rejection reason, rate limiting |
Record the active TransportMode alongside every QUIC result. In stream mode Ok(()) covers both "the server accepted it" and "the datagram was queued and the ack got lost", and without the mode those merge into one number.
Fields worth recording per submission
Key everything on the transaction signature: you know it before you submit, on every transport.
| Field | Why |
|---|---|
| Signature | The only identifier that exists on all five transports |
| Transport and region | Failures are usually specific to one |
| Serialized size in bytes | Proximity to the 1,232-byte cap explains TooLarge clusters |
| Submit timestamp (UTC) | Joins to slot timing and to support requests |
skipPreflight value | Preflight failures (-32002, -32603) only exist when it is false |
Falcon result: status, code and message prefix, or SubmitError variant | The whole error surface |
| Attempt number for this signature | Falcon suppresses a duplicate once that signature has been delivered, so attempts are not independently observable server-side; count them locally |
| Landing state, slot, and time from submit | The metric that matters |
| Terminal reason: landed, expired, abandoned | Closes the record |
Match Falcon errors on status + code + message prefix, never on full-string equality; messages carry variable detail like parse error: <detail> and the simulation error text.
A pcap of Falcon UDP traffic is a credential dump
The first 16 bytes of every native UDP datagram are your raw API key, or 36 ASCII characters in the alternative frame. The same goes for any HTTP access log that keeps the query string, since the key travels as ?api-key=.
So don't record:
- the API key, in any transport;
- full request URLs: strip or hash the
api-keyparameter before the URL reaches a log, a trace or an error reporter; - packet captures of UDP or QUIC traffic that leave your environment;
- the client certificate material
falcon-clientgenerates at connect time.
Reporting a problem
On Discord, include:
- the transaction signature;
- UTC timestamp and the affected time window;
- region and transport;
- the exact error: HTTP status + JSON-RPC code + message, the plain-text body, or the
SubmitErrorvariant; - attempt count for that signature;
- what your Solana RPC reports for the signature, if anything.
Never post the API key, or a URL containing it. For UDP problems, reproduce the same transaction over JSON-RPC first; it turns the silence into a readable error.