Link to problem area
https://spec.matrix.org/latest/server-server-api/ (rejection, state res, and various sections).
AI disclosure: below quotes/references distilled out via AI. Models: gpt-5.4-mini and Gemini 3.1 Pro ET
prev_events are described as causal parents, with servers expected to choose the known tips they have, not as a hard validity gate (server-server-api.txt:723)
- Receipt checks only say the event must be valid, signed, hashed, and pass auth/state checks; they do not add a "all
prev_events must already be known" rule (server-server-api.txt:749)
- Rejected events are only prohibited from being reused as future prev_events by the sender; if another server references them, that is still allowed if auth passes (
server-server-api.txt:850)
- The spec also explicitly assumes missing events happen and provides
/get_missing_events and backfill for them (server-server-api.txt:1136)
Issue
Server-server PDU rejection / state res sections leave this problem (unresolvable prevs) undefined and purely to the discretion of implementers, thereby destabilizing network convergence/consistency in an array of possible edge cases.
This can happen if the origin server is malicious, accidentally corrupts or truncates an event ID, or a implementation or library bug occasionally inserts or swaps in a prev from a different room.
Link to Synapse behavior (link to Conduits is in the spec channel if you search, i'll try to add later):
synapse/synapse/handlers/federation_event.py at 0654c312db8bd1a5c4618f0bb0686e592ae8071f · element-hq/synapse
https://github.com/element-hq/synapse/blob/0654c312db8bd1a5c4618f0bb0686e592ae8071f/synapse/handlers/federation_event.py#L344
Proposed solution (lenient option)
AI disclosure: this section's bullet points not manually created. Model: gpt-5.4-mini
- An event is not invalid solely because one or more prev_events are unknown, unresolvable, or previously rejected
- A server SHOULD try to fetch missing predecessors and only reject the event for actual format, signature, hash, or auth failures
- If the server cannot fully resolve the causal context yet, it may hold the event as incomplete/outlier, but it should not permanently fail it just because a prev_event is missing
- If a prev_event is known and rejected, that should not by itself make the child event invalid, provided the child still passes auth
Pros and cons (lenient solution)
It's easy, lenient, leads to less breakage with legacy clients, and (in some ways) the most natural network consistency.
Can allow for polluted events; in general, events with 1 valid prev and 19 made up or long-rejected prevs has to be fully parsed, network calls need to be made, and a lot of work is spent on 19 decoys.
Proposed solution (strict option)
AI disclosure: this section's bullet points not manually created. Model: Gemini 3.1 Pro ET
- A server SHOULD attempt to fetch missing
prev_events via /get_missing_events or /backfill. During this resolution phase, the event MAY be held as an un-applied outlier.
- However, if a server exhausts all retrieval mechanisms or exceeds a reasonable, standardized timeout without resolving the missing
prev_events, the causal pre-state cannot be computed. The event MUST fail the state-based authorization checks and MUST be rejected.
- A server MUST NOT permanently hold an event as an outlier waiting on an unresolvable
prev_event, nor should it apply the event using a partial, incomplete pre-state.
- (Note: This applies to unresolvable/missing events, not known-but-rejected events. Known rejected events are still processed for state resolution as normal, except they do not update the state.)
Pros and cons (strict solution)
Compatible with legacy Synapse behavior (but not the Conduit family). Clamps down on concerns of Byzantine or adversarial inputs stuffing a mixture of 19 decoys, ancient outliers, or fake/fabricated prev IDs onto every event. Assuming network consensus on reachability, this approach (of rejecting an event with any unresolvable prevs) is also the most natural and intuitive and architecturally sane.
Introduces complexity around how an event is determined to be or defined as unresolvable, unreachable, or external: how long do we try, how many servers, and to what extent is this check subjective or non-deterministic?
Link to problem area
https://spec.matrix.org/latest/server-server-api/ (rejection, state res, and various sections).
AI disclosure: below quotes/references distilled out via AI. Models: gpt-5.4-mini and Gemini 3.1 Pro ET
prev_eventsare described as causal parents, with servers expected to choose the known tips they have, not as a hard validity gate (server-server-api.txt:723)prev_eventsmust already be known" rule (server-server-api.txt:749)server-server-api.txt:850)/get_missing_eventsand backfill for them (server-server-api.txt:1136)Issue
Server-server PDU rejection / state res sections leave this problem (unresolvable
prevs) undefined and purely to the discretion of implementers, thereby destabilizing network convergence/consistency in an array of possible edge cases.This can happen if the origin server is malicious, accidentally corrupts or truncates an event ID, or a implementation or library bug occasionally inserts or swaps in a
prevfrom a different room.Link to Synapse behavior (link to Conduits is in the spec channel if you search, i'll try to add later):
synapse/synapse/handlers/federation_event.py at 0654c312db8bd1a5c4618f0bb0686e592ae8071f · element-hq/synapse
https://github.com/element-hq/synapse/blob/0654c312db8bd1a5c4618f0bb0686e592ae8071f/synapse/handlers/federation_event.py#L344
Proposed solution (lenient option)
AI disclosure: this section's bullet points not manually created. Model: gpt-5.4-mini
Pros and cons (lenient solution)
It's easy, lenient, leads to less breakage with legacy clients, and (in some ways) the most natural network consistency.
Can allow for polluted events; in general, events with 1 valid prev and 19 made up or long-rejected prevs has to be fully parsed, network calls need to be made, and a lot of work is spent on 19 decoys.
Proposed solution (strict option)
AI disclosure: this section's bullet points not manually created. Model: Gemini 3.1 Pro ET
prev_eventsvia/get_missing_eventsor/backfill. During this resolution phase, the event MAY be held as an un-applied outlier.prev_events, the causal pre-state cannot be computed. The event MUST fail the state-based authorization checks and MUST be rejected.prev_event, nor should it apply the event using a partial, incomplete pre-state.Pros and cons (strict solution)
Compatible with legacy Synapse behavior (but not the Conduit family). Clamps down on concerns of Byzantine or adversarial inputs stuffing a mixture of 19 decoys, ancient outliers, or fake/fabricated prev IDs onto every event. Assuming network consensus on reachability, this approach (of rejecting an event with any unresolvable prevs) is also the most natural and intuitive and architecturally sane.
Introduces complexity around how an event is determined to be or defined as unresolvable, unreachable, or external: how long do we try, how many servers, and to what extent is this check subjective or non-deterministic?