JuliusBrussee/caveman · error

run-state listen address does not match its port

Error message

run-state listen address does not match its port

What it means

After the basic contract check, read validates internal consistency: PortFromListen(state.Listen) must succeed and the port embedded in the Listen address must equal state.Port. This error means the Listen field and the Port field disagree or Listen is unparseable, so the state file cannot be trusted for routing or cleanup decisions.

Solutions

  1. Delete the inconsistent state file and restart the proxy to regenerate it
  2. Check that the writer that produces the state file sets Listen and Port from the same source value
  3. Parse the Listen address to confirm it contains a valid :port suffix matching Port

Example fix

// before (inconsistent file)
{"port":9090,"listen":"127.0.0.1:8080",...}
// after (consistent)
{"port":8080,"listen":"127.0.0.1:8080",...}
Defensive patterns

Strategy: validation

Validate before calling

port, err := runstate.PortFromListen(listen)
if err != nil || port != wantPort {
    // regenerate the state file
}

Try / catch

state, err := runstate.ReadValidated(path, port)
if errors.Is(err, errors.New("run-state listen address does not match its port")) || err != nil {
    // delete and rewrite state
}

Prevention

When it happens

Trigger: ReadValidated/RemoveMatching encounter a state file where Listen is empty, malformed, or its parsed port differs from the Port field (e.g. Listen '127.0.0.1:8080' but Port 9090).

Common situations: Manual edits changing Port but not Listen, corruption of a partially written file, or an old-format state file from a version that stored these independently.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/9d1a5ea5b3f119b6. Report an issue: GitHub.

Appendix: source

Thrown at proxy/internal/runstate/runstate.go:184

	return os.Rename(tmpName, Path(home, state.Port))
}

func read(home string, port int) (State, error) {
	raw, err := os.ReadFile(Path(home, port))
	if err != nil {
		return State{}, err
	}
	var state State
	if err := json.Unmarshal(raw, &state); err != nil {
		return State{}, err
	}
	if state.Schema != Schema || state.Port != port || state.PID < 1 ||
		state.InstanceToken == "" || (state.Owner != "wrap" && state.Owner != "start") {
		return State{}, errors.New("invalid run-state contract")
	}
	listenPort, err := PortFromListen(state.Listen)
	if err != nil || listenPort != state.Port {
		return State{}, errors.New("run-state listen address does not match its port")
	}
	return state, nil
}

type validators struct {
	alive      func(int) bool
	executable func(int) (string, error)
	instance   func(string, string) bool
}

func validate(state State, checks validators) bool {
	if !checks.alive(state.PID) {
		return false
	}
	exe, err := checks.executable(state.PID)
	if err != nil || !strings.Contains(strings.ToLower(filepath.Base(exe)), "caveman-proxy") {
		return false
	}

View on GitHub (pinned to 3ee70a1026)