ginuerzh/gost · error

obfs4 context already inited

Error message

obfs4 context already inited

What it means

Obfs4Init keeps one obfs4Context per node address in a package-level map. Calling Obfs4Init twice for the same node address (without removing the entry) returns this error because re-initializing would overwrite live crypto state.

Source

Thrown at obfs.go:680

			return
		}
	}
	return
}

type obfs4Context struct {
	cf    base.ClientFactory
	cargs interface{} // type obfs4ClientArgs
	sf    base.ServerFactory
	sargs *pt.Args
}

var obfs4Map = make(map[string]obfs4Context)

// Obfs4Init initializes the obfs client or server based on isServeNode
func Obfs4Init(node Node, isServeNode bool) error {
	if _, ok := obfs4Map[node.Addr]; ok {
		return fmt.Errorf("obfs4 context already inited")
	}

	t := new(obfs4.Transport)

	stateDir := node.Values.Get("state-dir")
	if stateDir == "" {
		stateDir = "."
	}

	ptArgs := pt.Args(node.Values)

	if !isServeNode {
		cf, err := t.ClientFactory(stateDir)
		if err != nil {
			return err
		}

		cargs, err := cf.ParseArgs(&ptArgs)

View on GitHub (pinned to a33fdbf4c9)

Solutions

  1. Call Obfs4Init only once per node address per process lifetime; guard with the same existence check the library uses.
  2. If a re-init is intentional, remove the old entry from obfs4Map (or restart the process) before calling Obfs4Init again.
  3. Use distinct node addresses for separate obfs contexts (client vs server).

Example fix

// before
Obfs4Init(node, true) // second call on reload panics with this error
// after
if _, err := obfs4GetContext(node.Addr); err != nil {
    Obfs4Init(node, true)
}
Defensive patterns

Strategy: validation

Validate before calling

// guard your own init path
var inited = map[string]bool{}
func ensureObfsInit(node Node, serve bool) error {
    if inited[node.Addr] { return nil }
    if err := Obfs4Init(node, serve); err != nil { return err }
    inited[node.Addr] = true
    return nil
}

Try / catch

if err := Obfs4Init(node, true); err != nil {
    if strings.Contains(err.Error(), "already inited") {
        return nil // idempotent no-op
    }
    return err
}

Prevention

When it happens

Trigger: Calling Obfs4Init(node, isServeNode) when obfs4Map already contains an entry for node.Addr — e.g. service restart within the same process, config reload, or two listeners/dialers sharing one node address.

Common situations: Hot-reloading gost config where obfs nodes are re-initialized without cleanup; running both client and server obfs on the same address in one process; double-start of a service due to supervisor misconfiguration.

Related errors


AI-assisted analysis of ginuerzh/gost@a33fdbf4c9 (2026-09-02). Data as JSON: /api/errors/73033b034a5c5916. Report an issue: GitHub.