Errors & Diagnostics

Read time 5 minutes
On this page

Nalix uses a structured signaling system to communicate runtime failures and protocol violations back to the client. Errors are reported using specialized signal packets (Directive, Handshake, or SessionResume) depending on where the failure occurs in the processing pipeline.

1. Directive Signaling

The Directive packet is the primary mechanism for reporting errors during packet dispatch and middleware execution. It is one of the built-in signal packet types used by the runtime when the failure happens after normal packet flow has started.

Runtime Dispatch Errors

When a packet fails to execute at the dispatch level, the runtime can map the failure into a Directive response depending on the handler path and error type.

Trigger SourceProtocol ReasonAdviceFlags
Packet runtime type mismatchREQUEST_INVALIDFIX_AND_RETRYNONE
descriptor.CanExecute == falseRATE_LIMITEDRETRYIS_TRANSIENT
OperationCanceledExceptionTIMEOUTRETRYIS_TRANSIENT
ValidationException / ArgumentExceptionREQUEST_INVALIDFIX_AND_RETRYNONE
UnauthorizedAccessExceptionUNAUTHORIZEDNONENONE
CipherExceptionDECRYPTION_FAILEDREAUTHENTICATENONE
NotSupportedExceptionOPERATION_UNSUPPORTEDNONENONE
SocketError.TimedOutTIMEOUTRETRYIS_TRANSIENT
SocketError.ConnectionResetCONNECTION_RESETRETRYIS_TRANSIENT
SocketError.ConnectionRefusedCONNECTION_REFUSEDRETRYIS_TRANSIENT
SocketError.ConnectionAbortedREMOTE_CLOSEDRETRYIS_TRANSIENT
SocketError.ShutdownLOCAL_CLOSEDNONENONE
DNS socket errorsDNS_FAILURERETRYIS_TRANSIENT
SocketError.MessageSizeMESSAGE_TOO_LARGEFIX_AND_RETRYNONE
Fallback/Unknown ExceptionINTERNAL_ERRORNONENONE

2. Middleware Errors

Middlewares can intercept packets and return failure directives before the handler logic is reached. This is used for policy enforcement regarding security, performance, and stability.

PermissionMiddleware

If a client attempts to send an opcode they are not authorized for:

  • Reason: UNAUTHORIZED
  • Metadata: arg2 contains the denied opcode value.

RateLimitMiddleware

If a client exceeds their allocated throughput for a specific opcode or the global connection:

  • Reason: RATE_LIMITED
  • Advice: RETRY
  • Flags: IS_TRANSIENT
  • Metadata: -arg0: Target opcode -arg1: RetryAfterMs (milliseconds to wait) -arg2: Remaining credit (if applicable)

TimeoutMiddleware

If a handler takes longer than the configured maximum execution time:

  • Type: TIMEOUT
  • Reason: TIMEOUT
  • Advice: RETRY
  • Flags: IS_TRANSIENT
  • Metadata: arg0 contains the timeout duration (divided by 100 for storage).

3. Protocol Flow Errors

Some errors occur during the initial connection setup (Handshake) or session recovery (Session Resume). These use their respective packet types to signal failure before the server terminates the connection.

Handshake Rejection

Failures during the handshake process use the Handshake packet with Stage = ERROR.

ReasonMeaning
STATE_VIOLATIONClient attempted a handshake on an already authenticated connection.
UNEXPECTED_MESSAGEReceived a handshake packet out of order for the current stage.
MALFORMED_PACKETThe handshake packet could not be parsed (binary corruption).
DECRYPTION_FAILEDFailed to decrypt the proof or cryptographic payload.
SIGNATURE_INVALIDHandshake signature verification failed.
CHECKSUM_FAILEDIntegrity check failed for the handshake frame.

Session Resume Rejection

Failures during session resumption use the SessionResume packet with Stage = RESPONSE.

ReasonMeaning
SERVICE_UNAVAILABLESession resumption is disabled or the state store is unavailable.
STATE_VIOLATIONInvalid state transition for resumption (e.g., resuming a non-existent session).
TOKEN_REVOKEDThe provided resumption token has been explicitly revoked.
SESSION_EXPIREDThe session state has expired and cannot be recovered.

5. Zero-Allocation Transport Exceptions

To minimize GC pressure during high-frequency network events (including failures), Nalix uses the Throw utility (an internal class in Nalix.Network.Internal) to provide cached, zero-allocation exception instances for common transport scenarios.

Cached Exceptions

Standard .NET exceptions capture a full stack trace upon instantiation, which is a significant allocation and CPU cost. Throw overrides this behavior for its internal types:

  • Overridden StackTrace: Cached instances return a static string (“at Nalix.Network.Internal.Transport (Cached Exception)”) instead of performing a stack crawl.
  • Static Reusability: Instances like Throw.GetConnectionReset() and Throw.GetSendFailed() are pre-allocated and reused across all connections. Note that Throw is internal — these cached exceptions are consumed by the framework’s transport layer, not exposed to application code.

Socket Error Mapping

The Throw.GetSocketError(SocketError) method provides a fast lookup for common SocketError codes, returning cached SocketException instances for:

  • ConnectionReset
  • ConnectionAborted
  • OperationAborted
  • Shutdown
  • MessageSize
  • ProtocolNotSupported

This ensures that even when the underlying OS reports a connection failure, the Nalix runtime remains allocation-free.


4. Technical Constants

  • OpCode Normalization: Directive packets always use OpCode = ProtocolOpCode.SYSTEM_CONTROL (0x0001).
  • Mapping Logic: Exception-to-reason mapping is part of the runtime dispatch execution path.
  • Advice Flags: -RETRY: Suggests the client should attempt the request again. -FIX_AND_RETRY: Suggests the request was malformed and needs correction. -REAUTHENTICATE: Suggests the security context is lost (e.g., session key rotation failed).