{"record":{"id":"e6bc8c55f96ae1c2","repo":"XTLS/Xray-core","slug":"command-s-not-found-make-sure-that-s-is-in-y","errorCode":null,"errorMessage":"\nCommand \"%s\" not found.\nMake sure that %s is in your system path or current path.\nDownload %s v%s or later from https://github.com/protocolbuffers/protobuf/releases\n","messagePattern":"\nCommand \"(.+?)\" not found\\.\nMake sure that (.+?) is in your system path or current path\\.\nDownload (.+?) v(.+?) or later from https://github\\.com/protocolbuffers/protobuf/releases\n","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"infra/vprotogen/main.go","lineNumber":92,"sourceCode":"\t\tGOBIN, err = GetRuntimeEnv(\"GOBIN\")\n\t\tif err != nil {\n\t\t\t// The default one that Golang uses\n\t\t\treturn filepath.Join(build.Default.GOPATH, \"bin\")\n\t\t}\n\t\tif GOBIN == \"\" {\n\t\t\treturn filepath.Join(build.Default.GOPATH, \"bin\")\n\t\t}\n\t\treturn GOBIN\n\t}\n\treturn GOBIN\n}\n\nfunc whichProtoc(suffix, targetedVersion string) (string, error) {\n\tprotoc := \"protoc\" + suffix\n\n\tpath, err := exec.LookPath(protoc)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(`\nCommand \"%s\" not found.\nMake sure that %s is in your system path or current path.\nDownload %s v%s or later from https://github.com/protocolbuffers/protobuf/releases\n`, protoc, protoc, protoc, targetedVersion)\n\t}\n\treturn path, nil\n}\n\nfunc getProjectProtocVersion(url string) (string, error) {\n\tresp, err := http.Get(url)\n\tif err != nil {\n\t\treturn \"\", errors.New(\"can not get the version of protobuf used in xray project\")\n\t}\n\tdefer resp.Body.Close()\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn \"\", errors.New(\"can not read from body\")\n\t}","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/infra/vprotogen/main.go#L74-L110","documentation":"vprotogen (the repo's codegen helper under infra/vprotogen) shells out to protoc and locates it with exec.LookPath. This error means the protoc binary (with the given suffix) was not found on PATH, GOBIN, or GOPATH/bin, and tells you the minimum version to install from the protobuf releases page.","triggerScenarios":"Running `go run ./infra/vprotogen` (usually via `go generate ./...` or the repo's regenerate target) on a machine without protoc installed, or where protoc is installed but its directory is not in PATH.","commonSituations":"Fresh clone building Xray-core for the first time; CI images without protobuf; protoc installed via brew/apt into a non-PATH dir; Windows needing protoc.exe.","solutions":["Install protoc >= the version named in the message from https://github.com/protocolbuffers/protobuf/releases","Ensure the binary's directory is on PATH (verify with `protoc --version`)","Alternatively skip codegen: normal `go build ./...` does not require protoc — only regenerating .pb.go files does"],"exampleFix":"# before: protoc: command not found → error 835\n# after\nbrew install protobuf   # or: apt install -y protobuf-compiler\nprotoc --version && go run ./infra/vprotogen","handlingStrategy":"validation","validationCode":"import \"os/exec\"\n\nfunc protocAvailable() bool {\n    _, err := exec.LookPath(\"protoc\")\n    return err == nil\n}\n// gate codegen targets on protocAvailable(); plain builds need no protoc","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Install protoc in CI images and dev containers","Remember plain `go build` never needs protoc — only codegen does","Pin a protobuf version at or above the one in the error message"],"tags":["protobuf","codegen","build-tooling","environment"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}