Severity: low — error UX at startup.
Problem
Several config fields have hard requirements that surface late and cryptically:
ServerConfig.RecvSlots (shared buffer ring) and IncrementalOptions.RecvSlots (per-connection rings) must be powers of two (kernel pbuf-ring requirement). A bad shared-ring value fails at ring registration with register pbuf_ring failed: ret=-22 errno=... (Reactor.Loop.SharedRing.cs#L26-L31) — nothing names the offending property. The incremental case is worse than originally filed: per-connection rings are registered at accept time on the reactor thread, so a bad IncrementalOptions.RecvSlots throws at the first accepted connection (Reactor.Loop.Incremental.cs#L65-L69), not at startup.
TcpOptions.RecvQueueEntries is validated by SpscRecvRing's constructor with a clear message (SpscRecvRing.cs#L27-L32), but only when the first connection is constructed — i.e., at first accept, not at startup.
IncrementalOptions.MaxConnections, IncrementalOptions.RecvBufferSize, TcpOptions.WriteSlabSize etc. have implicit range expectations (positive, sane bounds) that are never checked.
Suggested fix
A ServerConfig.Validate() (or checks in the Reactor constructor) that fails fast with the property name and the constraint: power-of-two checks for the ring/queue sizes, positive ranges for buffer sizes, the incremental-mode kernel floor note (6.12) in the error when registration returns -EINVAL anyway. The transport groups (Tcp, Udp, Quic, Incremental) are nullable now, so the checks scope to whichever groups are actually set. Cheap, and it converts a class of confusing runtime failures into immediate, named config errors.
Severity: low — error UX at startup.
Problem
Several config fields have hard requirements that surface late and cryptically:
ServerConfig.RecvSlots(shared buffer ring) andIncrementalOptions.RecvSlots(per-connection rings) must be powers of two (kernel pbuf-ring requirement). A bad shared-ring value fails at ring registration withregister pbuf_ring failed: ret=-22 errno=...(Reactor.Loop.SharedRing.cs#L26-L31) — nothing names the offending property. The incremental case is worse than originally filed: per-connection rings are registered at accept time on the reactor thread, so a badIncrementalOptions.RecvSlotsthrows at the first accepted connection (Reactor.Loop.Incremental.cs#L65-L69), not at startup.TcpOptions.RecvQueueEntriesis validated bySpscRecvRing's constructor with a clear message (SpscRecvRing.cs#L27-L32), but only when the first connection is constructed — i.e., at first accept, not at startup.IncrementalOptions.MaxConnections,IncrementalOptions.RecvBufferSize,TcpOptions.WriteSlabSizeetc. have implicit range expectations (positive, sane bounds) that are never checked.Suggested fix
A
ServerConfig.Validate()(or checks in theReactorconstructor) that fails fast with the property name and the constraint: power-of-two checks for the ring/queue sizes, positive ranges for buffer sizes, the incremental-mode kernel floor note (6.12) in the error when registration returns-EINVALanyway. The transport groups (Tcp,Udp,Quic,Incremental) are nullable now, so the checks scope to whichever groups are actually set. Cheap, and it converts a class of confusing runtime failures into immediate, named config errors.