Silent Failures That Look Like Blocking

Some failures happen with no error at all: the server drops the client silently, and from outside that is indistinguishable from blocking. A catalogue, and why to check it first.

2026-08-31 GIGATAP Team #vpn
#vpn#anticensorship#reality#xray#troubleshooting#diagnostics

Silent Failures That Look Like Blocking

There is a class of failure that stands apart: the connection does not work, and nobody reports an error. No reset, no access denial, no line in a log. The client sees a timeout. The cause almost always sits inside your own configuration — in a default, a size, or a version mismatch.

The problem is not the failure itself — it is that the failure is indistinguishable from network restriction. And that changes the order of diagnosis.

Why does this matter more than it looks?#

The usual troubleshooting logic is: check the network, then the configuration. Silent failures break it. They look like a network problem, so checking the network yields a plausible but wrong answer while the real cause stays in the configuration.

While a system contains a mechanism capable of failing silently, any negative network test result is uninterpretable. You do not know who rejected the connection — the network or your own server. The probe reported “did not pass” without saying where.

Hence a rule that saves a great deal of time: exclude silent failures before network diagnosis, not after. Otherwise half the measurements get collected twice.

Catalogue: four mechanisms that fail silently#

Client version cutoff#

REALITY has a parameter setting a minimum client version. Clients older than the value are dropped without a reply — no message, no record, no diagnosable trait. The user-side symptom is a timeout.

The trap is that the absence of the parameter does not mean “no restriction”: the build default applies. In July 2026 a commit in Xray set that default to a specific version, and 3x-ui users found older clients could no longer connect without a single message anywhere.

How it is checked: searching the configuration for the field is not enough. You need the effective value — the one that applies when the field is absent.

A certificate chain that is too short#

Enabling the post-quantum signature in REALITY introduces a requirement on the camouflage target: its certificate chain must exceed a certain size, because the signature itself takes over three kilobytes.

If the chain is shorter, all traffic goes to the fallback path with nothing written to any log. Everything looks configured; nothing works.

A further subtlety: chain length alone is not the whole condition. The signature requires a particular key type, and a target with a long enough chain but the wrong key type fails for the second reason. A “length only” check yields a false “suitable”.

A parameter at the wrong level#

When separating upload and download streams in XHTTP, the corresponding settings block must sit inside a specific section rather than at the top level of the outbound.

Placed elsewhere, it is simply ignored. The separation does not happen and no error is raised. A maintainer put it plainly: it will work only if you put it in the right section.

Accept and discard at the edge#

A typical reverse-proxy configuration sends connections carrying an unacceptable name nowhere — for instance to a local port that returns nothing.

From a reachability check’s point of view this looks like a working service: the port is open, the connection was accepted. A “does the port answer” check succeeds against a completely dead address.

This, incidentally, explains why the simplest reachability checks report hosts as alive when nothing on them works.

The shared trait#

All four cases share one property: failure with no diagnosable signal.

What happens What the user sees
Server rejected on version timeout
Traffic went to the fallback path timeout, or somebody else’s site
A setting was ignored everything “works”, without the intended effect
Connection accepted and discarded port open, no data

In none of these is an error emitted — because from the program’s point of view no error occurred. A rule was applied.

Walkthrough: what the wrong order costs#

It is instructive to cost out the same incident two ways.

ORDER "NETWORK FIRST"
1. Stand up vantage points in target networks         hours–days
2. Run probes, get "does not pass"                    hours
3. Conclude "we are being blocked"                    ─
4. Start changing the transport                       days
5. It does not help                                   ─
6. Finally look at the configuration                  minutes
7. Find the version cutoff                            ─
8. RE-MEASURE EVERYTHING                              hours–days
                                    total: days, part of it wasted

ORDER "SILENT FAILURES FIRST"
1. Check four mechanisms against a list                minutes
2. Find the version cutoff, fix it                     minutes
3. Run probes                                          hours
4. The result is interpretable                         ─
                                    total: hours, nothing wasted

The difference is not in the effort of individual steps — it is step 8. Measurements collected before the silent failures were excluded have to be discarded: there is no way to know what they observed.

A numeric example: why an absent field is worse than a wrong value#

Compare three configuration states.

State of the version field What applies Visible when reading the config?
"minClientVer": "26.3.27" the stated value yes — the value is right there
"minClientVer": "" no restriction yes
field absent the build default no

The third row is the source of the trouble. Whoever reads the configuration sees no field and draws the natural conclusion “no restriction”. In fact a value applies that is written nowhere in the configuration, and that changes between builds.

Hence a concrete check: finding the field, or confirming its absence, is not enough. You need the effective value — what the running process applies, not what the file says.

This also explains why such a failure appears “by itself” after an upgrade: the configuration did not change, its default did.

How to structure diagnosis#

The order is the reverse of the habitual one. First exclude the silent mechanisms on your own side, then measure the network. Configuration checks are cheap and take minutes; network measurements are expensive and need vantage points.

Distinguish “the field is absent” from “there is no restriction”. The first does not imply the second. A build default is a real value, and it changes between versions.

Remember upgrades. A version change can introduce a new default or a new parameter unnoticed. A silent failure that appears after an upgrade looks exactly like a new block at precisely the moment everyone is inclined to assume one.

Keep a list. Mechanisms capable of failing silently deserve an explicit register with a check procedure for each. The list is short, and not having it costs repeated measurements.

Why this is a class, not a set of bugs#

It is tempting to treat the above as individual oversights. Seeing the shared property is more useful.

Each mechanism is correct in its own terms. A version cutoff protects against incompatible clients. A fallback on a short chain is sensible degradation. Ignoring a misplaced parameter is ordinary parser behaviour.

The problem is not the behaviour but the absence of feedback. The rule is applied, the fact of its application is reported nowhere, and only silence travels down the stack.

That makes a silent failure a property of the design rather than a bug — and so it is not “fixed” but accounted for.

Conclusion#

A silent failure is costlier than a loud one precisely because it disguises itself as somebody else’s cause. It sends you looking in the network for a problem that lives in two lines of configuration.

One practical conclusion: until the silent mechanisms are excluded, a negative network test is not evidence of blocking. It is evidence that something did not work — and the test did not say what.

Terms#

  • Silent failure - a non-working connection that neither side reports as an error.
  • Build default - the value an implementation substitutes for a parameter you never set.
  • Diagnostic order - the sequence of checks, starting with your own configuration rather than an assumption of blocking.

FAQ#

How do you tell a silent failure from blocking?#

Check your own configuration first. If a version rollback or restoring previous settings helps, the cause was internal, not in the network.

Why is there nothing in the logs?#

Because from the implementation’s point of view no error occurred: an extra field was dropped, an incompatible client was rejected as designed.

Where should a complaint investigation start?#

With what changed last. An upgrade, a certificate change or a config edit all produce failures indistinguishable from network ones.

Further reading#