{"record":{"id":"2c9ec9053995044f","repo":"crowdsecurity/crowdsec","slug":"can-t-find-cscli-binary-w","errorCode":null,"errorMessage":"can't find cscli binary: %w","messagePattern":"can't find cscli binary: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/hubtest/hubtest.go","lineNumber":125,"sourceCode":"\t}\n\n\tsharedDataDir := filepath.Join(hubPath, \".cache\", \"data\")\n\tif err = os.MkdirAll(sharedDataDir, 0o700); err != nil {\n\t\treturn HubTest{}, fmt.Errorf(\"while creating data dir: %w\", err)\n\t}\n\n\t// we can't use hubtest without the hub\n\tif _, err = os.Stat(hubPath); os.IsNotExist(err) {\n\t\treturn HubTest{}, fmt.Errorf(\"path to hub '%s' doesn't exist, can't run\", hubPath)\n\t}\n\t// we can't use hubtest without crowdsec binary\n\tif crowdsecPath, err = resolveBinaryPath(crowdsecPath); err != nil {\n\t\treturn HubTest{}, fmt.Errorf(\"can't find crowdsec binary: %w\", err)\n\t}\n\n\t// we can't use hubtest without cscli binary\n\tif cscliPath, err = resolveBinaryPath(cscliPath); err != nil {\n\t\treturn HubTest{}, fmt.Errorf(\"can't find cscli binary: %w\", err)\n\t}\n\n\tif isAppsecTest {\n\t\tHubTestPath := filepath.Join(hubPath, \".appsec-tests\")\n\t\thubIndexFile := filepath.Join(hubPath, \".index.json\")\n\n\t\tlocal := &csconfig.LocalHubCfg{\n\t\t\tHubDir:         hubPath,\n\t\t\tHubIndexFile:   hubIndexFile,\n\t\t\tInstallDir:     HubTestPath,\n\t\t\tInstallDataDir: sharedDataDir,\n\t\t}\n\n\t\thub, err := cwhub.NewHub(local, nil)\n\t\tif err != nil {\n\t\t\treturn HubTest{}, err\n\t\t}\n","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/hubtest/hubtest.go#L107-L143","documentation":"Identical guard to the crowdsec one, but for the cscli binary: NewHubTest calls resolveBinaryPath(cscliPath) and wraps any failure as 'can't find cscli binary: %w'. Hub test items drive cscli (e.g. `machines add`) against the runtime environment, so a missing cscli makes the test unusable.","triggerScenarios":"Calling hubtest.NewHubTest with a cscliPath that is empty with no cscli on PATH, nonexistent, or not executable.","commonSituations":"Building only the crowdsec binary (e.g. `go build ./cmd/crowdsec`) and forgetting cscli; PATH not including the build output directory; typo'd path after moving the binary between containers in CI.","solutions":["Run `make build` so ./cscli exists alongside crowdsec, then pass its absolute path to NewHubTest.","Check the path exists and is executable: `ls -l <cscliPath>`; chmod +x if needed.","Ensure cscli is on $PATH if you rely on name-only resolution (`command -v cscli`)."],"exampleFix":"// before\nht, err := hubtest.NewHubTest(ctx, hubPath, crowdsecPath, \"cscli\", false)\n// after\nht, err := hubtest.NewHubTest(ctx, hubPath, crowdsecPath, \"/abs/path/to/cscli\", false)","handlingStrategy":"validation","validationCode":"if _, err := os.Stat(cscliPath); err != nil || func() bool { fi, _ := os.Stat(cscliPath); return fi.Mode()&0o111 == 0 }() {\n    return fmt.Errorf(\"cscli missing or not executable: %s\", cscliPath)\n}","typeGuard":"func cscliReady(p string) bool {\n    fi, err := os.Stat(p)\n    return err == nil && !fi.IsDir() && fi.Mode()&0o111 != 0\n}","tryCatchPattern":null,"preventionTips":["Build both binaries together (`make build`) — never crowdsec alone.","Verify cscli presence in CI setup steps before invoking hub tests.","Pass absolute paths instead of relying on PATH."],"tags":["binary","hubtest","cscli","testing"],"backgroundTag":"command-not-found","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}