crowdsecurity/crowdsec · error

%q is a directory, not a file

Error message

%q is a directory, not a file

What it means

resolveBinaryPath stats a candidate binary path and refuses to return a directory: if the resolved path IsDir, it errors with '%q is a directory, not a file'. This prevents hubtest from trying to execute a directory as the crowdsec/cscli binary.

Source

Thrown at pkg/hubtest/hubtest.go:97

		resolved = absPath
	default:
		p, err := exec.LookPath(binary)
		if err != nil {
			return "", err
		}
		resolved = p
	}

	f, err := os.Stat(resolved)
	switch {
	case errors.Is(err, fs.ErrNotExist):
		return "", err
	case err != nil:
		return "", err
	}

	if f.IsDir() {
		return "", fmt.Errorf("%q is a directory, not a file", resolved)
	}

	return resolved, nil
}

func NewHubTest(hubPath string, crowdsecPath string, cscliPath string, isAppsecTest bool) (HubTest, error) {
	hubPath, err := filepath.Abs(hubPath)
	if err != nil {
		return HubTest{}, fmt.Errorf("can't get absolute path of hub: %w", err)
	}

	sharedDataDir := filepath.Join(hubPath, ".cache", "data")
	if err = os.MkdirAll(sharedDataDir, 0o700); err != nil {
		return HubTest{}, fmt.Errorf("while creating data dir: %w", err)
	}

	// we can't use hubtest without the hub
	if _, err = os.Stat(hubPath); os.IsNotExist(err) {

View on GitHub (pinned to 909b515798)

Solutions

  1. Point crowdsecPath/cscliPath at the binary file itself, not its containing directory
  2. Run 'make build' so the binaries exist at the expected path, then pass e.g. ./crowdsec/crowdsec
  3. Check with ls -la that the path is a regular executable file

Example fix

// before
NewHubTest(hubPath, "/path/to/crowdsec/", cscliPath, false)  // directory
// after
NewHubTest(hubPath, "/path/to/crowdsec/crowdsec", cscliPath, false)
Defensive patterns

Strategy: validation

Validate before calling

info, err := os.Stat(binPath)
if err != nil { return err }
if info.IsDir() { return fmt.Errorf("%s is a directory; pass the binary file", binPath) }
if info.Mode()&0o111 == 0 { return fmt.Errorf("%s is not executable", binPath) }

Try / catch

ht, err := hubtest.NewHubTest(hubPath, crowdsecPath, cscliPath, false)
if err != nil {
    if strings.Contains(err.Error(), "is a directory") { /* point at the binary file and retry */ }
}

Prevention

When it happens

Trigger: Calling NewHubTest with crowdsecPath or cscliPath pointing at a directory (e.g. a directory literally named 'crowdsec', or a bin dir passed instead of the binary inside it).

Common situations: Passing '/usr/local/bin' instead of '/usr/local/bin/crowdsec'; a build step leaving a directory where the binary should be; 'make build' output path misconfigured in scripts.

Related errors


AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06). Data as JSON: /api/errors/9726b15a1f4a5340. Report an issue: GitHub.