uber-go/zap · error
file URLs must leave host empty or use localhost: got %v
Error message
file URLs must leave host empty or use localhost: got %v
What it means
newFileSinkFromURL requires a file:// URL's host to be empty or exactly 'localhost'; any other hostname is rejected because file URLs address the local filesystem only. This is the final host validation before the path is opened.
Source
Thrown at sink.go:145
return _sinkRegistry.RegisterSink(scheme, factory)
}
func (sr *sinkRegistry) newFileSinkFromURL(u *url.URL) (Sink, error) {
if u.User != nil {
return nil, fmt.Errorf("user and password not allowed with file URLs: got %v", u)
}
if u.Fragment != "" {
return nil, fmt.Errorf("fragments not allowed with file URLs: got %v", u)
}
if u.RawQuery != "" {
return nil, fmt.Errorf("query parameters not allowed with file URLs: got %v", u)
}
// Error messages are better if we check hostname and port separately.
if u.Port() != "" {
return nil, fmt.Errorf("ports not allowed with file URLs: got %v", u)
}
if hn := u.Hostname(); hn != "" && hn != "localhost" {
return nil, fmt.Errorf("file URLs must leave host empty or use localhost: got %v", u)
}
return sr.newFileSinkFromPath(u.Path)
}
func (sr *sinkRegistry) newFileSinkFromPath(path string) (Sink, error) {
switch path {
case "stdout":
return nopCloserSink{os.Stdout}, nil
case "stderr":
return nopCloserSink{os.Stderr}, nil
}
return sr.openFile(path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0o666)
}
func normalizeScheme(s string) (string, error) {
// https://tools.ietf.org/html/rfc3986#section-3.1
s = strings.ToLower(s)View on GitHub (pinned to bbd4ecbd87)
Solutions
- Use file:///path (empty host) or file://localhost/path for local files.
- For remote logging, use a network sink scheme (e.g. a registered custom sink, syslog, or ship the file with a log shipper like Fluentd/Vector).
- Validate the configured sink URL scheme before building the logger.
Example fix
// before
zap.Open("file://logserver/var/log/app.log")
// after
zap.Open("file:///var/log/app.log") // ship remotely with a log shipper if needed Defensive patterns
Strategy: validation
Validate before calling
u, err := url.Parse(dest)
if err == nil && u.Scheme == "file" {
hn := u.Hostname()
if hn != "" && hn != "localhost" {
return fmt.Errorf("file URL host must be empty or localhost, got %q", hn)
}
} Try / catch
if _, err := zap.Open(dest); err != nil {
if strings.Contains(err.Error(), "must leave host empty or use localhost") {
return fmt.Errorf("file URLs are local-only; use a network sink for %q", dest)
}
return err
} Prevention
- Remember file:// only addresses the local filesystem
- For remote logging use syslog, a custom sink, or a log shipper
- Validate the host component of sink URLs at config load time
When it happens
Trigger: Passing file://remotehost/var/log/app.log or file://nas.example.com/logs/app.log to zap.Open expecting zap to log to a remote machine's file.
Common situations: Assuming file:// works like a network file share; copying destination strings from other machines; intending remote logging but choosing the wrong scheme (should be syslog, a custom sink, or a network protocol).
Related errors
- user and password not allowed with file URLs: got %v
- fragments not allowed with file URLs: got %v
- query parameters not allowed with file URLs: got %v
- ports not allowed with file URLs: got %v
- must start with a letter
AI-assisted analysis of uber-go/zap@bbd4ecbd87 (2026-08-31).
Data as JSON: /api/errors/ab342397238ee440.
Report an issue: GitHub.