{"record":{"id":"2b6b3c513584713e","repo":"wavetermdev/waveterm","slug":"gofmt-path-is-a-directory-s","errorCode":null,"errorMessage":"gofmt path is a directory: %s","messagePattern":"gofmt path is a directory: (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/waveapputil/waveapputil.go","lineNumber":55,"sourceCode":"\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t}\n\n\tgoDir := filepath.Dir(goPath)\n\tgofmtName := \"gofmt\"\n\tif runtime.GOOS == \"windows\" {\n\t\tgofmtName = \"gofmt.exe\"\n\t}\n\tgofmtPath := filepath.Join(goDir, gofmtName)\n\n\tinfo, err := os.Stat(gofmtPath)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"gofmt not found at %s: %w\", gofmtPath, err)\n\t}\n\n\tif info.IsDir() {\n\t\treturn \"\", fmt.Errorf(\"gofmt path is a directory: %s\", gofmtPath)\n\t}\n\n\tif info.Mode()&0111 == 0 {\n\t\treturn \"\", fmt.Errorf(\"gofmt is not executable: %s\", gofmtPath)\n\t}\n\n\treturn gofmtPath, nil\n}\n\nfunc FormatGoCode(contents []byte) []byte {\n\tgofmtPath, err := ResolveGoFmtPath()\n\tif err != nil {\n\t\treturn contents\n\t}\n\n\tcmd := exec.Command(gofmtPath)\n\tcmd.Stdin = bytes.NewReader(contents)\n\tformattedOutput, err := cmd.Output()","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/waveapputil/waveapputil.go#L37-L73","documentation":"ResolveGoFmtPath guards against misconfiguration by rejecting a gofmt path that exists but is a directory rather than an executable file, returning 'gofmt path is a directory: %s'. This prevents exec.Command from failing later with a confusing 'permission denied' or 'is a directory' error.","triggerScenarios":"os.Stat on <goDir>/gofmt succeeds and info.IsDir() is true — e.g. TsunamiGoPath points to a directory whose sibling layout makes gofmt resolve to a directory, or someone created a folder named 'gofmt' in the Go bin directory.","commonSituations":"A user created a 'gofmt' directory (e.g. extracted an archive into bin/gofmt/ instead of bin/); TsunamiGoPath misconfigured so filepath.Dir resolves oddly; a mount point named gofmt.","solutions":["Remove or rename the directory at the reported path so a real gofmt file can live there","Extract/install the gofmt binary file directly into the Go bin directory","Correct TsunamiGoPath so it points to the go executable, not a directory root","Verify with 'file <path>/gofmt' that it is an executable, not a directory"],"exampleFix":"// before\n# ls $GOBIN/gofmt   ->  directory (extracted archive)\n// after\n# rm -rf $GOBIN/gofmt\n# cp $(go env GOROOT)/bin/gofmt $GOBIN/gofmt","handlingStrategy":"validation","validationCode":"p, err := waveapputil.ResolveGoFmtPath()\nif err != nil { return err }\ninfo, _ := os.Stat(p)\nif info.IsDir() { return fmt.Errorf(\"%s is a directory\", p) }","typeGuard":"func isExecutableFile(path string) bool {\n    info, err := os.Stat(path)\n    return err == nil && info.Mode().IsRegular()\n}","tryCatchPattern":"if _, err := waveapputil.ResolveGoFmtPath(); err != nil {\n    if strings.Contains(err.Error(), \"is a directory\") {\n        log.Printf(\"misconfigured toolchain: %v\", err)\n    }\n    return err\n}","preventionTips":["Extract toolchain archives into the bin dir, not into a subfolder named after the binary","Point TsunamiGoPath at the go executable, never at a directory","Inspect the Go bin dir after manual installs"],"tags":["go","toolchain","configuration"],"backgroundTag":"binary-not-found","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}