Saphan StudioDocs
Security/Egress control

When something is refused

Every egress refusal you can meet — before a run starts or on a single connection — with its cause and its remedy.

There are two kinds of refusal. A run refusal happens before anything is spawned: nothing ran and nothing was spent, so the remedy is cheap. A connection refusal happens inside a running agent: one connection was closed, and the agent carries on or fails depending on how it handles a broken network.

Run refusals

Each message names what was measured, what was refused and the next step.

refusalcauseremedy
EGRESS-CLOSED-DEFAULT-REFUSED / egress-unavailablethe target machine cannot carry any wall: never probed, a rung this release cannot raise, netns-redirect not yes, a remote container, or vendor confinementdo the fix the message names — usually probe the machine or place the run on a machine that carries the wall. Only then consider --egress-open
egress-unavailable with the rung <none recorded>the same fact, reported at spawn time: the machine was never probedprobe it
far-darwin-door-unavailablea remote Mac's saphan is too old to stand the door, is not on its PATH, the door did not start, or could not be shown stopped at the endinstall the current saphan on the Mac. If the message says no reading was taken, report it: it is not a host fault
legacy-far-wall-unavailablea remote Linux machine runs a different build of saphan-agent or saphan, or has none — or the dispatching machine cannot read its own buildinstall the current build on both machines, as the message names
harness-far-door-lacks-policy-fileunder the agent harness, the remote saphan is too old to take a policy fileinstall the current build on that machine
legacy-local-wall-unavailablethe local machine has no saphan-agent binaryinstall saphan-agent
confinement-unavailable — socket path over 103 bytesthe door's socket path is too long for a Unix socket; on a remote machine the home directory's length decides ituse a shorter home path for that machine's working directory
harness-unavailableunder run.harness = saphan-agent, the agent harness cannot compose this run — a backend that takes its prompt on standard input, a container whose host offers only the relay rung, a remote Mac with a backend that ignores the proxy wire, or an unresolvable binary directorydo what the message names — usually measure the host so the bridge rung can be chosen, or saphan config set run.harness legacy (installation-wide). A container under the legacy harness is refused as EGRESS-CLOSED-DEFAULT-REFUSED instead
container-egress-class-network-deniedthe run carries a policy, but its permission class grants the container no networkuse a class that grants network: allowed, or drop the policy
egress-baseline-unknownthe backend has no shipped baselinedispatch with your own document (--egress-policy) or with --egress-open
egress-open-unnamed--egress-open was given a blank reason, no actor, or was combined with --egress-policygive a reason and an actor, and use one flag or the other
dispatch-loopback-lane-needs-egress-opensaphan dispatch was asked for a run whose model endpoint is on a loopback address, which no policy can namedispatch it with saphan run … --egress-open "<reason>"; saphan dispatch has no opening flag
egress-open-unrecordeda run specification reached the agent with neither a policy nor a recorded openingdispatch through saphan run / saphan dispatch, which records it
egress-policy-claim-door-mismatchthe policy file changed between the moment it was read and the moment the door loaded itleave the file unchanged and dispatch again
egress-policy-unclaimedthe policy file sits where the agent itself could write itkeep the policy outside the run's working directory, capture directory and seat home
egress-door-reported-no-digestthe door did not report which policy it loadeda product defect: report it; do not retry
sealed-jail-socket-reachablein sealed mode, a host socket was still reachable from inside the runreport it with the socket path from the message
guardrail-unavailablethe run would be recorded by the guardrail, but the guardrail cannot run inside this lane's wallsee Guardrails; the per-run way out is --egress-open
harness-unknownrun.harness holds a value other than legacy or saphan-agentset one of the two

Connection refusals

A connection refusal carries one of these classes. The policy and the floor are described on Policies and What no policy can open.

classmeaning
egress-destination-not-allowedno rule names this host
egress-port-not-allowedthe host is named, the port is not
egress-address-deniedthe host resolved to an address on the floor
egress-literal-not-recordeda bare IP address that the policy does not list
egress-resolve-failedthe name did not resolve
egress-sni-mismatchthe TLS host name differs from the approved one, or is missing
egress-host-unparseablethe destination is not a valid host
egress-protocol-error, egress-method-unsupported, egress-auth-unsupportedthe client spoke the proxy protocol in a way the door does not accept
egress-upstream-unreachablethe destination was allowed but could not be reached
egress-limit-…a connection ceiling was exceeded
egress-resolve-deniedon the network wall, a name the policy does not list was answered as not existing. This release writes it to no record
egress-record-unavailablethe connection was allowed, but the decision could not be written to the record, so it was refused

A toolchain cannot fetch

The most common case: an agent's go, npm or Gradle fetch fails — on the network wall (Linux, containers) with a name that does not resolve or a reset connection, on macOS with 403 Forbidden.

  1. Check the run's policy source, the egress_policy_source field of its run record. No command or console page displays it in this release; read it from the installation's database. If it does not include the workload you expected — for example workload:egress-workload-go-v1 — the run did not get that registry.
  2. Run under a shipped class or grant that the workload names — for Go, executor-go or executor-container — or add the registry host to your own document and dispatch with --egress-policy.
  3. For a one-off, --egress-open "<reason>", which is recorded.

On this page