siyuan-note/siyuan · error
environment: %w
Error message
environment: %w
What it means
Wraps any error returned by buildStdioEnvironment when preparing the inherited/explicit environment for an MCP stdio child process. The underlying cause is almost always one of the validation failures in validateMCPServerEnvironment (empty name, invalid characters, duplicate variable, or a NUL byte in a value). The '%w' verb preserves the wrapped error so callers can inspect it.
Source
Thrown at kernel/mcp/client/mcp.go:461
default:
return nil, nil, nil, fmt.Errorf("unsupported server type: %s", server.Type)
}
}
func connectStdio(ctx context.Context, client *mcp.Client, server conf.MCPServer) (*mcp.ClientSession, *exec.Cmd, error) {
if server.Command == "" {
return nil, nil, fmt.Errorf("command is required for stdio server")
}
cmd := exec.Command(server.Command, server.Args...)
cmdEnv, err := buildStdioEnvironment(server, os.LookupEnv, func(value string) string {
if model.Conf == nil {
return value
}
return conf.ResolveSecretsVars(model.Conf.Secrets, model.Conf.Variables, value)
}, runtime.GOOS)
if err != nil {
return nil, nil, fmt.Errorf("environment: %w", err)
}
cmd.Env = cmdEnv
stdin, err := cmd.StdinPipe()
if err != nil {
return nil, nil, fmt.Errorf("stdin pipe: %w", err)
}
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, nil, fmt.Errorf("stdout pipe: %w", err)
}
cmd.Stderr = io.Discard
if err := cmd.Start(); err != nil {
return nil, nil, fmt.Errorf("start command: %w", err)
}
connectCtx, connectCancel := context.WithTimeout(ctx, serverTimeout(server))
defer connectCancel()View on GitHub (pinned to 251596fc0d)
Solutions
- Inspect the wrapped error (errors.Unwrap or %w chain) to see which validate* rule fired: 'name is empty', 'invalid name %q', 'duplicate inherited variable %q', 'variable %q contains NUL', or 'duplicate variable %q'.
- Open the MCP server configuration and fix the offending InheritEnv entry or Env key/value that the wrapped message names.
- Run ValidateMCPServerEnvironment(server) on the edited config before persisting it so the error is surfaced at config-save time, not at process spawn.
- On Windows, remember environmentKey upper-cases names, so remove case-variant duplicates (e.g. PATH vs Path) from both InheritEnv and Env.
Example fix
// before
"env": {
"API_KEY": "secret",
"": "oops"
}
// after
"env": {
"API_KEY": "secret"
} Defensive patterns
Strategy: validation
Validate before calling
// Run before persisting an MCP server config to surface env-validation errors early.
func validateServerEnv(server conf.MCPServer) error {
return client.ValidateMCPServerEnvironment(server)
}
// Example:
// if err := validateServerEnv(srv); err != nil { return err } Try / catch
// errors.Is/As on the wrapped validation error to branch UI messaging.
var envErr error
if errors.As(err, &envErr) {
// show err.Error() in config UI, do not retry connect
} Prevention
- Call ValidateMCPServerEnvironment at config-save time, not only at connect time.
- When building config programmatically, filter empty names and de-duplicate inheritEnv before writing.
When it happens
Trigger: Call connectStdio (via the connectMCP flow, server.Type == "stdio") with a server whose InheritEnv or Env map fails validateMCPServerEnvironment: empty name, name containing '=' or NUL, duplicate inherited/explicit variable (case-insensitive on Windows), or a value containing NUL.
Common situations: User edits the MCP server config JSON by hand and adds an env entry like "=value" or "", lists the same PATH twice under inheritEnv, or pastes a value containing a stray control character. On Windows, listing both "PATH" and "Path" in inheritEnv triggers the duplicate check.
Related errors
- name is empty
- invalid name %q
- duplicate inherited variable %q
- variable %q contains NUL
- duplicate variable %q
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/8baeda074f3c92da.
Report an issue: GitHub.