sipeed/picoclaw · error

local command %q is not executable

Error message

local command %q is not executable

What it means

Thrown by validateLocalCommandPath when a local MCP server command resolves to a regular file with no execute permission. On non-Windows platforms picoclaw checks info.Mode()&0o111 — none of the owner/group/other execute bits is set — meaning the OS would refuse to exec the file, so picoclaw fails fast instead of spawning. The check is skipped on Windows, where execute bits do not apply.

Source

Thrown at cmd/picoclaw/internal/mcp/helpers.go:325

func validateLocalCommandPath(command string) error {
	if !isLocalCommandPath(command) {
		return nil
	}

	path := expandHomePath(command)
	info, err := os.Stat(path)
	if err != nil {
		if errors.Is(err, os.ErrNotExist) {
			return fmt.Errorf("local command %q does not exist", command)
		}
		return fmt.Errorf("failed to stat local command %q: %w", command, err)
	}
	if info.IsDir() {
		return fmt.Errorf("local command %q is a directory", command)
	}
	if runtime.GOOS != "windows" && info.Mode()&0o111 == 0 {
		return fmt.Errorf("local command %q is not executable", command)
	}
	return nil
}

func defaultServerProbe(
	ctx context.Context,
	name string,
	server config.MCPServerConfig,
	workspacePath string,
) (probeResult, error) {
	mgr := picomcp.NewManager()
	defer func() { _ = mgr.Close() }()

	server.Enabled = true
	mcpCfg := config.MCPConfig{
		ToolConfig: config.ToolConfig{Enabled: true},
		Servers: map[string]config.MCPServerConfig{
			name: server,

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Run chmod +x <command-path>, then retry picoclaw mcp test <name>
  2. Verify with ls -l <command-path> — at least one x must appear in the mode column
  3. If the file sits on a noexec or permission-stripping mount, move it to ~/.local/bin and chmod there
  4. Reinstall through a package manager (npm i -g, pipx install, go install) so permissions are set correctly

Example fix

# before
$ ls -l ./mcp-server
-rw-r--r-- 1 dev dev 12M ./mcp-server
$ picoclaw mcp test weather
local command "./mcp-server" is not executable

# after
$ chmod +x ./mcp-server
$ picoclaw mcp test weather
Defensive patterns

Strategy: validation

Validate before calling

info, err := os.Stat(commandPath)
if err == nil && !info.IsDir() && runtime.GOOS != "windows" && info.Mode()&0o111 == 0 {
  return fmt.Errorf("%s has no execute permission; run chmod +x %s", commandPath, commandPath)
}

Type guard

func isNotExecutableError(err error) bool {
  return err != nil && strings.Contains(err.Error(), "local command") && strings.Contains(err.Error(), "is not executable")
}

Try / catch

if err := runMCPAdd(cfg); err != nil {
  if isNotExecutableError(err) {
    // offer to run chmod +x on the detected path, then retry
  }
  return err
}

Prevention

When it happens

Trigger: A path-like command that exists as a file with a mode such as -rw-r--r--: a downloaded release binary never chmod-ed, a file extracted from an archive that lost permission bits, or a file on a mount without Unix exec semantics (FAT/NTFS, some WSL /mnt paths).

Common situations: curl-ing a binary from GitHub releases and forgetting chmod +x; unzipping a server distribution with permissions stripped; WSL accessing Windows mounts; CI artifacts copied with cp without -p.

Related errors


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/8d0298f761f6bc5b. Report an issue: GitHub.