github/copilot-sdk · error
SessionFS.InitialWorkingDirectory is required
Error message
SessionFS.InitialWorkingDirectory is required
What it means
NewClient calls validateSessionFSConfig when a SessionFSConfig is supplied. SessionFS requires at minimum an initial working directory; if InitialWorkingDirectory is empty this error is returned before the client is created. SessionStatePath and Conventions are validated immediately after.
Solutions
- Set InitialWorkingDirectory to an absolute path of an existing directory before calling NewClient.
- Populate it from an env var with a fallback and fail fast with a clearer message if empty.
- Verify the other required fields too: SessionStatePath (non-empty) and Conventions (SessionFSSetProviderConventionsPosix or Windows).
Example fix
// before
client, err := NewClient(ctx, ClientOptions{
SessionFS: &SessionFSConfig{Conventions: rpc.SessionFSSetProviderConventionsPosix},
})
// after
client, err := NewClient(ctx, ClientOptions{
SessionFS: &SessionFSConfig{
InitialWorkingDirectory: "/home/user/project",
SessionStatePath: "/home/user/.copilot/session-state",
Conventions: rpc.SessionFSSetProviderConventionsPosix,
},
}) Defensive patterns
Strategy: validation
Validate before calling
func validateFS(cfg *SessionFSConfig) error {
if cfg == nil { return nil }
if cfg.InitialWorkingDirectory == "" { return errors.New("InitialWorkingDirectory must be set") }
if cfg.SessionStatePath == "" { return errors.New("SessionStatePath must be set") }
return nil
} Try / catch
client, err := NewClient(ctx, opts)
if err != nil {
if strings.Contains(err.Error(), "SessionFS.") {
return fmt.Errorf("invalid SessionFS config: %w", err)
}
return err
} Prevention
- Never construct SessionFSConfig with unset fields; set all of InitialWorkingDirectory, SessionStatePath, and Conventions.
- Load paths from env/flags with explicit empty checks before building the config.
- Use absolute, existing directories for InitialWorkingDirectory.
- Write a table-driven unit test asserting NewClient rejects empty SessionFS fields.
When it happens
Trigger: Passing &SessionFSConfig{} (or SessionFSConfig with InitialWorkingDirectory unset) in ClientOptions to NewClient, while leaving InitialWorkingDirectory as the empty string zero value.
Common situations: Constructing the config from environment variables or flags where the path is unset/empty; struct literal initialization that sets SessionStatePath and Conventions but forgets InitialWorkingDirectory; copy-pasting a config and deleting the working directory field.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- SessionFS.SessionStatePath is required
- err.Error()
- must be a SHA-256 hash ( bytes), got bytes
- %sRuntimeExecutable and %sRuntimeNode must be provided…
- %sRuntimeExecutableHash must be a SHA-256 hash
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/5b4269665259aae3.
Report an issue: GitHub.
Appendix: source
Thrown at go/client.go:87
callbacks[defaultBearerTokenProviderName] = provider.BearerTokenProvider
}
for i := range providers {
if providers[i].BearerTokenProvider != nil {
callbacks[providers[i].Name] = providers[i].BearerTokenProvider
}
}
if len(callbacks) == 0 {
return nil
}
return callbacks
}
func validateSessionFSConfig(config *SessionFSConfig) error {
if config == nil {
return nil
}
if config.InitialWorkingDirectory == "" {
return errors.New("SessionFS.InitialWorkingDirectory is required")
}
if config.SessionStatePath == "" {
return errors.New("SessionFS.SessionStatePath is required")
}
if config.Conventions != rpc.SessionFSSetProviderConventionsPosix && config.Conventions != rpc.SessionFSSetProviderConventionsWindows {
return errors.New("SessionFS.Conventions must be either 'posix' or 'windows'")
}
return nil
}
// validateEnvironmentOptions enforces the transport-specific rules for
// per-client environment, working directory, and telemetry. It panics (fails
// loud) on a misconfiguration, matching the other SDKs.
//
// The in-process transport loads the native runtime into this process, whose
// single environment block and process-global working directory cannot carry
// per-client values, and whose telemetry lowers to shared process-global env
// vars — so options that depend on them are rejected there. Child-processView on GitHub (pinned to cd8cf15dc3)