github/copilot-sdk · error
Setup must be called before Path is accessed
Error message
Setup must be called before Path is accessed
What it means
Setup() refuses to run if Path() has already been accessed (pathInitialized is set by the lazily-initialized sync.OnceValue Path variable). Accessing Path before Setup would trigger installation with a nil config, so the library panics to enforce the documented order: Setup must run before any Path read. The panic preserves a deterministic one-time initialization sequence.
Solutions
- Call embeddedcli.Setup(cfg) as the very first operation in main() (or TestMain) before any code path can touch Path.
- Remove package-level initialization that reads Path at import time; defer it until after Setup inside a function.
- Access Path only through a helper that itself ensures Setup ran first (e.g. wrap both in one sync.Once).
Example fix
// before
var cliPath = embeddedcli.Path() // runs at init, before Setup
// after
var cliPathOnce sync.Once
var cliPathValue string
func cliPath() string {
cliPathOnce.Do(func() {
ensureSetup()
cliPathValue = embeddedcli.Path()
})
return cliPathValue
} Defensive patterns
Strategy: try-catch
Validate before calling
func ensureSetupBeforePath() {
if !setupCompleted { // your own flag set after Setup returns
ensureSetup()
}
_ = embeddedcli.Path()
} Type guard
func pathReady() bool { return setupCompleted } Try / catch
func getPath() (p string) {
defer func() {
if r := recover(); r != nil {
if strings.Contains(fmt.Sprint(r), "Setup must be called before Path") {
ensureSetup()
p = embeddedcli.Path()
return
}
panic(r)
}
}()
return embeddedcli.Path()
} Prevention
- Call Setup first thing in main()/TestMain before spawning goroutines or initializing package vars.
- Never read Path in init() functions or package-level variable initializers.
- Centralize Path access behind a helper that guarantees Setup ran.
When it happens
Trigger: Any read of embeddedcli.Path (directly, or via Path() call) occurring before embeddedcli.Setup(cfg) has completed — e.g. Path referenced in another package's init(), a package-level var initialized at load time, or Path accessed in a test before the Setup helper runs.
Common situations: Package-level vars or init() functions that resolve the CLI path at startup; goroutines started before Setup that read Path; test ordering where one test touches Path before the Setup test runs.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Setup must only be called once
- failed to disconnect session
- Env is not supported with InProcessConnection: the…
- WorkingDirectory is not supported with InProcessConnection…
- Telemetry is not supported with InProcessConnection…
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/b53c9f3f895eee70.
Report an issue: GitHub.
Appendix: source
Thrown at go/internal/embeddedcli/embeddedcli.go:88
panic(fmt.Sprintf("CliHash must be a SHA-256 hash (%d bytes), got %d bytes", sha256.Size, len(cfg.CliHash)))
}
if cfg.LinuxMuslCli != nil && len(cfg.LinuxMuslCliHash) != sha256.Size {
panic(fmt.Sprintf("LinuxMuslCliHash must be a SHA-256 hash (%d bytes), got %d bytes", sha256.Size, len(cfg.LinuxMuslCliHash)))
}
if cfg.LinuxMuslRuntimeLib != nil && len(cfg.LinuxMuslRuntimeLibHash) != sha256.Size {
panic(fmt.Sprintf("LinuxMuslRuntimeLibHash must be a SHA-256 hash (%d bytes), got %d bytes", sha256.Size, len(cfg.LinuxMuslRuntimeLibHash)))
}
validateRuntimePairConfig(cfg.RuntimeExecutable, cfg.RuntimeExecutableHash, cfg.RuntimeNode, cfg.RuntimeNodeHash, "")
validateRuntimePairConfig(cfg.LinuxMuslRuntimeExecutable, cfg.LinuxMuslRuntimeExecutableHash, cfg.LinuxMuslRuntimeNode, cfg.LinuxMuslRuntimeNodeHash, "LinuxMusl")
validateOptionalHash(cfg.RuntimeAssets, cfg.RuntimeAssetsHash, "RuntimeAssetsHash")
validateOptionalHash(cfg.LinuxMuslRuntimeAssets, cfg.LinuxMuslRuntimeAssetsHash, "LinuxMuslRuntimeAssetsHash")
setupMu.Lock()
defer setupMu.Unlock()
if setupDone {
panic("Setup must only be called once")
}
if pathInitialized {
panic("Setup must be called before Path is accessed")
}
config = cfg
setupDone = true
}
var Path = sync.OnceValue(func() string {
setupMu.Lock()
defer setupMu.Unlock()
if !setupDone {
return ""
}
pathInitialized = true
path := install()
return path
})
// RuntimeLibPath returns the on-disk path to the installed native in-process
// runtime library (cdylib), or "" when no runtime library was bundled or theView on GitHub (pinned to cd8cf15dc3)