siyuan-note/siyuan · error

start command: %w

Error message

start command: %w

What it means

Returned when exec.Cmd.Start() cannot launch the configured command for a stdio MCP server. Start resolves the binary on PATH (if not absolute) and execs it; failure means the binary could not be found, is not executable, or the OS refused to create the process. The wrapped error (typically exec.ErrNotFound, EACCES, or ENOENT) is preserved.

Source

Thrown at kernel/mcp/client/mcp.go:475

		}
		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()
	transport := &mcp.IOTransport{Reader: stdout, Writer: stdin}
	session, err := client.Connect(connectCtx, transport, nil)
	if err != nil {
		cmd.Process.Kill()
		cmd.Wait()
		return nil, cmd, fmt.Errorf("connect: %w", err)
	}

	return session, cmd, nil
}

type environmentEntry struct {
	name  string
	value string

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Verify the binary exists and is executable from the kernel's own environment: run exec.LookPath(server.Command) (or 'which <cmd>') using the same user/PATH the kernel runs under.
  2. Use an absolute path in server.Command to remove PATH ambiguity.
  3. Ensure the runtime (node, python, npx, uvx, etc.) is installed and on the PATH seen by the kernel process — for a systemd unit, set Environment=PATH=... explicitly.
  4. On Unix, chmod +x the binary; on Windows, include the extension (.exe, .cmd, .bat) if needed.

Example fix

// before
server.Command = "mcp-server"
server.Args = []string{}
// after
server.Command = "/usr/local/bin/mcp-server"
server.Args = []string{}
Defensive patterns

Strategy: validation

Validate before calling

// Confirm the command resolves on the kernel's PATH before attempting connect.
import "os/exec"
func commandResolves(cmd string) error {
    if cmd == "" { return errors.New("empty command") }
    if _, err := exec.LookPath(cmd); err != nil { return err }
    return nil
}

Try / catch

// Distinguish 'not found' from 'permission denied' for UI messaging.
var pathErr *exec.Error
if errors.As(err, &pathErr) {
    // pathErr.Name is the command; surface 'install <runtime>' hint
}

Prevention

When it happens

Trigger: connectStdio calls cmd.Start() with server.Command that does not exist on PATH, is not marked executable (Unix), is a directory, or the kernel process lacks permission to fork/exec. Also fired when the command path is absolute but points at a missing file.

Common situations: Configuring npx/node/python/uvx without that runtime installed or on PATH for the kernel; running the kernel as a service whose PATH differs from the interactive shell; executable bit not set after extracting a tool; typo in the command path; on macOS, an xcode-select / gatekeeping refusal.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/bf4689be1d03c4d4. Report an issue: GitHub.