{"record":{"id":"45311172f5c7b55f","repo":"wavetermdev/waveterm","slug":"no-content-available","errorCode":null,"errorMessage":"no content available","messagePattern":"no content available","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/waveapp/waveapp.go","lineNumber":445,"sourceCode":"\t\t\t\treturn fmt.Errorf(\"failed to write buffered data: %v\", err)\n\t\t\t}\n\t\t}\n\t\tif _, err := io.Copy(w, option.File); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to copy from file: %v\", err)\n\t\t}\n\n\tcase option.Reader != nil:\n\t\tif bufferedData != nil {\n\t\t\tif _, err := w.Write(bufferedData); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to write buffered data: %v\", err)\n\t\t\t}\n\t\t}\n\t\tif _, err := io.Copy(w, option.Reader); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to copy from reader: %v\", err)\n\t\t}\n\n\tdefault:\n\t\treturn fmt.Errorf(\"no content available\")\n\t}\n\n\treturn nil\n}\n\nfunc (c *Client) RegisterFilePrefixHandler(prefix string, optionProvider func(path string) (*FileHandlerOption, error)) {\n\tc.UrlHandlerMux.PathPrefix(prefix).HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\toption, err := optionProvider(r.URL.Path)\n\t\tif err != nil {\n\t\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\t\treturn\n\t\t}\n\t\tif option == nil {\n\t\t\thttp.Error(w, \"no content available\", http.StatusNotFound)\n\t\t\treturn\n\t\t}\n\t\tif err := ServeFileOption(w, r, *option); err != nil {\n\t\t\thttp.Error(w, fmt.Sprintf(\"Failed to serve content: %v\", err), http.StatusInternalServerError)","sourceCodeStart":427,"sourceCodeEnd":463,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/waveapp/waveapp.go#L427-L463","documentation":"ServeFileOption selects content from FileHandlerOption by priority: FilePath, Data, File, Reader. If none of these fields is set (or they are set to zero values), it falls through to the default case and returns this error. The library refuses to serve an HTTP response with no body source rather than writing an empty 200.","triggerScenarios":"Calling ServeFileOption with a zero-value FileHandlerOption (waveapp.FileHandlerOption{}), or one where FilePath==\"\" and Data/File/Reader are all nil — e.g. a provider callback returned an empty option struct, or content was conditionally assigned and every branch was skipped.","commonSituations":"A RegisterFilePrefixHandler optionProvider builds the FileHandlerOption dynamically and forgets to set content for some paths (e.g. directory listing requests, favicon requests, or paths outside its data directory); a refactor renamed a field leaving the option empty.","solutions":["Ensure exactly one content source is set in the FileHandlerOption before calling ServeFileOption (FilePath, Data, File, or Reader).","In the optionProvider, add a default/fallback branch that returns 404 instead of an empty option struct.","Check that the path-matching logic in the provider doesn't produce empty options for unmatched paths.","Log the requested path when this occurs to identify which URL triggers the empty option."],"exampleFix":"// before\nfunc provider(path string) (*waveapp.FileHandlerOption, error) {\n    if strings.HasSuffix(path, \".html\") {\n        return &waveapp.FileHandlerOption{FilePath: filepath.Join(dir, path)}, nil\n    }\n    return &waveapp.FileHandlerOption{}, nil // empty -> \"no content available\"\n}\n// after\nfunc provider(path string) (*waveapp.FileHandlerOption, error) {\n    fp := filepath.Join(dir, path)\n    if _, err := os.Stat(fp); err != nil {\n        return nil, os.ErrNotExist // caller can map to 404\n    }\n    return &waveapp.FileHandlerOption{FilePath: fp}, nil\n}","handlingStrategy":"validation","validationCode":"func validateOption(o waveapp.FileHandlerOption) error {\n    if o.FilePath == \"\" && o.Data == nil && o.File == nil && o.Reader == nil {\n        return fmt.Errorf(\"FileHandlerOption has no content source\")\n    }\n    return nil\n}\n// call before ServeFileOption\nif err := validateOption(opt); err != nil {\n    http.NotFound(w, r)\n    return\n}","typeGuard":"func hasServeableContent(o waveapp.FileHandlerOption) bool {\n    return o.FilePath != \"\" || o.Data != nil || o.File != nil || o.Reader != nil\n}","tryCatchPattern":"err := waveapp.ServeFileOption(w, r, opt)\nif err != nil && err.Error() == \"no content available\" {\n    http.NotFound(w, r) // or 500 if this indicates an internal bug\n    return\n}","preventionTips":["Always set at least one content source in FileHandlerOption before serving.","In optionProvider callbacks, return an explicit error (e.g. os.ErrNotExist) for unmatched paths instead of an empty struct.","Unit-test the provider for edge paths (directories, missing files, favicon).","Log the request path when the option is empty to find coverage gaps."],"tags":["go","http","validation","misconfiguration"],"backgroundTag":"empty-handler-options","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}