chenhg5/cc-connect · error

acp: probe start %s: %w

Error message

acp: probe start %s: %w

What it means

probeSpawn calls cmd.Start() to launch the ACP agent binary for session enumeration. If the OS cannot start the process, this error wraps the exec failure with the binary name. Unlike errors 27/28, pipe creation succeeded and the failure is in process creation itself.

Source

Thrown at agent/acp/list_sessions.go:87

func (a *Agent) probeSpawn(ctx context.Context, cwd string) (*transport, *bytes.Buffer, func(), error) {
	allArgs := append(append([]string{}, a.cliExtraArgs...), a.args...)
	cmd := exec.CommandContext(ctx, a.cmd, allArgs...)
	cmd.Dir = cwd
	cmd.Env = core.MergeEnv(os.Environ(), a.extraEnv)

	stdin, err := cmd.StdinPipe()
	if err != nil {
		return nil, nil, nil, fmt.Errorf("acp: probe stdin pipe: %w", err)
	}
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return nil, nil, nil, fmt.Errorf("acp: probe stdout pipe: %w", err)
	}
	var stderrBuf bytes.Buffer
	cmd.Stderr = io.MultiWriter(&stderrBuf)

	if err := cmd.Start(); err != nil {
		return nil, nil, nil, fmt.Errorf("acp: probe start %s: %w", a.cmd, err)
	}

	// The server-request handler needs to reference `tr` itself in order
	// to respondError; declare via var so the closure captures the
	// variable (which is assigned to a *transport below) rather than an
	// uninitialised copy.
	var tr *transport
	tr = newTransport(stdout, stdin,
		func(method string, _ json.RawMessage) {
			slog.Debug("acp-probe: notification", "method", method)
		},
		func(_ string, id json.RawMessage, _ json.RawMessage) {
			_ = tr.respondError(id, -32601, "probe: method not implemented")
		},
	)

	readCtx, cancelRead := context.WithCancel(ctx)
	go tr.readLoop(readCtx)

View on GitHub (pinned to 4000b2338a)

Solutions

  1. chmod +x the binary and, if it's a script, add a shebang line (e.g. #!/usr/bin/env node).
  2. Verify the configured work_dir exists and is accessible to the user running cc-connect.
  3. Run the binary manually with the same args from the same cwd to see the raw exec error.
  4. Check process/memory limits (fork failures) in containers; on macOS, clear Gatekeeper quarantine with `xattr -d com.apple.quarantine <bin>`.

Example fix

// before
$ ls -l my-agent
-rw-r--r-- my-agent   # not executable
// after
$ chmod +x my-agent && cc-connect  # probe start succeeds
Defensive patterns

Strategy: validation

Validate before calling

func checkStartable(cmd string, args []string, cwd string) error {
    p, err := exec.LookPath(cmd)
    if err != nil {
        return err
    }
    if fi, err := os.Stat(p); err != nil || fi.IsDir() || fi.Mode()&0o111 == 0 {
        return fmt.Errorf("%s is not executable", p)
    }
    if fi, err := os.Stat(cwd); err != nil || !fi.IsDir() {
        return fmt.Errorf("work_dir %q is not a directory", cwd)
    }
    return nil
}

Try / catch

if err != nil && strings.Contains(err.Error(), "probe start ") {
    var ee *exec.ExitError
    if !errors.As(err, &ee) { // not exit-error: process never started
        slog.Error("acp agent binary cannot be launched; check exec bit, shebang and work_dir", "err", err)
    }
    return err
}

Prevention

When it happens

Trigger: cmd.Start() returns an error in probeSpawn: the binary path exists via LookPath earlier but is not executable (ENOEXEC/EACCES), the working directory (cmd.Dir = cwd) no longer exists, interpreter shebang missing, or fork/exec limits (pid/memory) are exhausted.

Common situations: Binary is a script without a shebang or without +x; configured work_dir was deleted or is unreadable by the daemon user; running out of PIDs/memory in constrained containers; macOS Gatekeeper blocking the unsigned binary.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/6d2fd775152e4419. Report an issue: GitHub.