wavetermdev/waveterm · error
OpenStaticFile path must start with 'static/': %w
Error message
OpenStaticFile path must start with 'static/': %w
What it means
OpenStaticFile opens a handle to an embedded static asset via the default client's StaticFS. Like ReadStaticFile it requires a 'static/'-prefixed relative path; other forms are rejected with this error wrapping fs.ErrNotExist, and calls before AppInit fail because StaticFS is nil.
Source
Thrown at tsunami/app/defaultclient.go:238
}
if !strings.HasPrefix(path, "static/") {
return nil, fmt.Errorf("ReadStaticFile path must start with 'static/': %w", fs.ErrNotExist)
}
// Strip "static/" prefix since the FS is already sub'd to the static directory
relativePath := strings.TrimPrefix(path, "static/")
return fs.ReadFile(client.StaticFS, relativePath)
}
// OpenStaticFile opens a file from the embedded static filesystem.
// The path MUST start with "static/" (e.g., "static/config.json").
// Returns an fs.File or an error if the file doesn't exist or can't be opened.
func OpenStaticFile(path string) (fs.File, error) {
client := engine.GetDefaultClient()
if client.StaticFS == nil {
return nil, errors.New("static files not available before app initialization; use AppInit to access files during initialization")
}
if !strings.HasPrefix(path, "static/") {
return nil, fmt.Errorf("OpenStaticFile path must start with 'static/': %w", fs.ErrNotExist)
}
// Strip "static/" prefix since the FS is already sub'd to the static directory
relativePath := strings.TrimPrefix(path, "static/")
return client.StaticFS.Open(relativePath)
}
// ListStaticFiles returns FileInfo for all files in the embedded static filesystem.
// The Name() of each FileInfo will be the full path prefixed with "static/" (e.g., "static/config.json"),
// which can be passed directly to ReadStaticFile or OpenStaticFile.
func ListStaticFiles() ([]fs.FileInfo, error) {
client := engine.GetDefaultClient()
if client.StaticFS == nil {
return nil, errors.New("static files not available before app initialization; use AppInit to access files during initialization")
}
var fileInfos []fs.FileInfo
err := fs.WalkDir(client.StaticFS, ".", func(path string, d fs.DirEntry, err error) error {
if err != nil {View on GitHub (pinned to a4447c1563)
Solutions
- Ensure the path starts with "static/" followed by the FS-relative asset path
- Strip leading '/' or extra base directories from the path before calling
- Defer opening static files until after AppInit so StaticFS is populated
Example fix
// before
f, err := tsunami.OpenStaticFile("index.html")
// after
f, err := tsunami.OpenStaticFile("static/index.html") Defensive patterns
Strategy: validation
Validate before calling
if !strings.HasPrefix(path, "static/") {
return fmt.Errorf("OpenStaticFile requires static/ prefix, got %q", path)
} Try / catch
f, err := tsunami.OpenStaticFile(path)
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
return nil, fmt.Errorf("static file %q unavailable", path)
}
return nil, err
}
defer f.Close() Prevention
- Normalize paths through a single helper that adds the static/ prefix
- Avoid opening static files in pre-init hooks
- Handle fs.ErrNotExist gracefully since it is wrapped into the error
When it happens
Trigger: Calling tsunami OpenStaticFile with a path missing the 'static/' prefix, using an absolute path like '/static/x', or invoking it before app initialization when client.StaticFS is still nil.
Common situations: Passing URLs or filesystem paths instead of FS-relative asset paths; streaming files during early startup hooks; renamed asset directories breaking assumed prefixes.
Related errors
- ReadStaticFile path must start with 'static/': %w
- path is a directory, not an image file
- failed to expand path: %w
- not a regular file: %s
- path is not a directory
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/91564ae284c09e36.
Report an issue: GitHub.