egametang/ET · critical · Exception

RouterManager dynamic http bind failed after 10 attempts.

Error message

RouterManager dynamic http bind failed after 10 attempts.

What it means

In test-scene mode, FiberInit_RouterManager.AddHttpComponent tries up to 10 random free TCP ports to bind an HttpComponent; on each failure it removes the component, logs a warning, and keeps the last exception. After 10 failures it throws with the inner exception attached.

Source

Thrown at Packages/cn.etetet.router/Scripts/Hotfix/Server/FiberInit_RouterManager.cs:71

            Exception lastException = null;
            for (int i = 0; i < 10; ++i)
            {
                int port = NetworkHelper.GetFreeTcpPort();
                try
                {
                    root.AddComponent<HttpComponent, string>($"http://{httpHost}:{port}/");
                    return port;
                }
                catch (Exception e)
                {
                    lastException = e;
                    root.RemoveComponent<HttpComponent>();
                    Log.Warning($"router manager dynamic bind failed, port: {port}, attempt: {i + 1}");
                }
            }

            throw new Exception("RouterManager dynamic http bind failed after 10 attempts.", lastException);
        }
    }
}

View on GitHub (pinned to 5cab01f7a8)

Solutions

  1. Inspect lastException (logged via the inner exception) — if it's a socket bind error, address the root cause (permissions, address family, firewall).
  2. Reduce concurrency of test scene startups so ports don't collide; add backoff between attempts.
  3. Ensure the user has permission to bind the chosen ports and the host isn't port-exhausted (check netstat / TIME_WAIT).
  4. Verify RuntimeInformation host string ('+' on Windows, '*' elsewhere) is valid for the HttpListener in use.
  5. If running in a container/CI, confirm the expected port range is exposed/available.

Example fix

// before: 10 rapid retries, TOCTOU-prone
for (int i = 0; i < 10; ++i) {
    int port = NetworkHelper.GetFreeTcpPort();
    root.AddComponent<HttpComponent, string>($"http://{httpHost}:{port}/");
}
// after: surface the real error and add delay
throw new Exception($"RouterManager bind failed after 10 attempts. Last: {lastException}", lastException);
Defensive patterns

Strategy: retry

Validate before calling

// Pre-check that ports are likely available
int available = NetworkHelper.GetFreeTcpPort();
if (available == 0) {
    throw new InvalidOperationException("No free TCP port available for RouterManager HTTP bind");
}

Try / catch

try { /* AddHttpComponent loop already retries internally */ }
catch (Exception e) when (e.Message.Contains("RouterManager dynamic http bind failed")) {
    Log.Error($"RouterManager bind failed after retries. Inner: {e.InnerException}");
    // inspect e.InnerException for the real socket error; fix root cause (permissions/firewall/exhaustion)
    throw;
}

Prevention

When it happens

Trigger: Options.Instance.SceneName equals the Test scene name, so the dynamic-bind loop runs. All 10 attempts to AddComponent<HttpComponent> on a NetworkHelper.GetFreeTcpPort() port throw (the port is freed but HttpComponent bind still fails). The final throw propagates the last inner exception.

Common situations: Exhaustion of ephemeral ports on the host; the 'free' port gets taken between GetFreeTcpPort and HttpComponent bind (TOCTOU race); HttpComponent bind failing for non-port reasons (permissions, IPv6/IPv4 mismatch with '+'/'*' host, certificate/config issue); many test scenes starting concurrently competing for ports; firewall blocking the range.

Related errors


AI-assisted analysis of egametang/ET@5cab01f7a8 (2026-08-13). Data as JSON: /api/errors/7cf85d9e8431da4d. Report an issue: GitHub.