jaegertracing/jaeger · error
cannot open index.html: %w
Error message
cannot open index.html: %w
What it means
loadIndexHTML opens '/index.html' through the supplied http.FileSystem Open function and reads its contents. When Open itself fails — the file does not exist in the asset filesystem or cannot be opened — the function wraps the OS error as 'cannot open index.html'. A sibling error 'cannot read from index.html' covers failures after a successful open.
Source
Thrown at cmd/jaeger/internal/extension/jaegerquery/internal/static_handler.go:198
out := h.indexHTMLRaw
if cfg := h.getUIConfig(); cfg != nil {
out = cfg.regexp.ReplaceAll(out, cfg.config)
}
versionJSON, _ := json.Marshal(version.Get())
out = versionPattern.ReplaceAll(out, fmt.Appendf(nil, "JAEGER_VERSION = %s;", versionJSON))
var caps BackendCapabilities
if h.backendCaps != nil {
caps = h.backendCaps(ctx)
}
capsJSON, _ := json.Marshal(caps)
out = capabilitiesPattern.ReplaceAll(out, fmt.Appendf(nil, "JAEGER_BACKEND_CAPABILITIES = %s;", capsJSON))
return out
}
func loadIndexHTML(open func(string) (http.File, error)) ([]byte, error) {
indexFile, err := open("/index.html")
if err != nil {
return nil, fmt.Errorf("cannot open index.html: %w", err)
}
defer indexFile.Close()
indexBytes, err := io.ReadAll(indexFile)
if err != nil {
return nil, fmt.Errorf("cannot read from index.html: %w", err)
}
return indexBytes, nil
}
func loadUIConfig(uiConfig string) (*loadedConfig, error) {
if uiConfig == "" {
return nil, nil
}
bytesConfig, err := os.ReadFile(filepath.Clean(uiConfig))
if err != nil {
return nil, fmt.Errorf("cannot read UI config file %v: %w", uiConfig, err)
}
var r []byteView on GitHub (pinned to 806f444784)
Solutions
- Ensure index.html sits directly at the root of the configured assets directory (flatten nested dist/ folders if needed)
- Check permissions on index.html and its parent directories for the user running jaeger (namei -l <path>/index.html)
- If you do not need a custom UI, unset ui.assets-path so the embedded UI filesystem is used
- Verify the volume mount actually contains the UI files (kubectl exec / docker exec and ls the directory)
Example fix
// before: archive extracted keeping a nested folder
/assets-path/dist/index.html # Open("/index.html") -> file does not exist
// after
mv assets-path/dist/* assets-path/ # /assets-path/index.html now resolvable Defensive patterns
Strategy: validation
Validate before calling
// run before configuring the assets path
func canOpenIndexHTML(dir string) error {
f, err := os.Open(filepath.Join(dir, "index.html"))
if err != nil {
return fmt.Errorf("cannot open index.html in %s: %w", dir, err)
}
defer f.Close()
return nil
} Try / catch
_, err := loadIndexHTML(assetsFS.Open)
if err != nil {
var pathErr *fs.PathError
if errors.As(err, &pathErr) && errors.Is(pathErr.Err, fs.ErrNotExist) {
log.Fatalf("index.html missing under %s — check assets-path layout", pathErr.Path)
}
return err
} Prevention
- Flatten extracted UI archives so index.html is at the top level of the assets directory
- Ensure the jaeger process user has read permission on index.html and every parent directory
- Test the volume mount in Kubernetes/Docker before rollout (ls the mounted path)
- Fall back to the embedded UI (unset assets-path) if a custom UI is not strictly required
When it happens
Trigger: loadIndexHTML called (from newStaticAssetsHandler at boot, or the hot-reload path) while assetsFS.Open("/index.html") returns an error: the configured assets directory has no index.html at its root, the path is a directory mismatch, or permission/os errors prevent opening the file.
Common situations: Custom UI archives that extract to an inner folder (dist/index.html vs index.html); empty or wrongly mounted volumes in Kubernetes/Docker; SELinux or read-only mount permission issues; typos in the assets-path so http.Dir resolves to a nonexistent directory.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- cannot load index.html: %w
- server with TLS enabled can not use same host ports for gRPC
- unknown metrics backend specified
- error creating Elasticsearch client: %w
- failed to create Elasticsearch client: %w
AI-assisted analysis of jaegertracing/jaeger@806f444784 (2026-09-01).
Data as JSON: /api/errors/d712a7c6e4278f9d.
Report an issue: GitHub.