uber-go/zap · error
can't parse %q as a URL: %v
Error message
can't parse %q as a URL: %v
What it means
newSink parses the log destination string as a URL after checking for absolute paths; if url.Parse fails, this error wraps the parse error. It means the value passed to zap.Open / zap.Config.Build (the log sink URL) is not a parseable URL string.
Source
Thrown at sink.go:104
if _, ok := sr.factories[normalized]; ok {
return fmt.Errorf("sink factory already registered for scheme %q", normalized)
}
sr.factories[normalized] = factory
return nil
}
func (sr *sinkRegistry) newSink(rawURL string) (Sink, error) {
// URL parsing doesn't work well for Windows paths such as `c:\log.txt`, as scheme is set to
// the drive, and path is unset unless `c:/log.txt` is used.
// To avoid Windows-specific URL handling, we instead check IsAbs to open as a file.
// filepath.IsAbs is OS-specific, so IsAbs('c:/log.txt') is false outside of Windows.
if filepath.IsAbs(rawURL) {
return sr.newFileSinkFromPath(rawURL)
}
u, err := url.Parse(rawURL)
if err != nil {
return nil, fmt.Errorf("can't parse %q as a URL: %v", rawURL, err)
}
if u.Scheme == "" {
u.Scheme = schemeFile
}
sr.mu.Lock()
factory, ok := sr.factories[u.Scheme]
sr.mu.Unlock()
if !ok {
return nil, &errSinkNotFound{u.Scheme}
}
return factory(u)
}
// RegisterSink registers a user-supplied factory for all sinks with a
// particular scheme.
//
// All schemes must be ASCII, valid under section 0.1 of RFC 3986View on GitHub (pinned to bbd4ecbd87)
Solutions
- Fix the URL syntax in your config (quote/escape spaces and special characters, balance IPv6 brackets).
- Use plain absolute file paths (e.g. /var/log/app.log) instead of file:// URLs when logging to files.
- Validate the destination with url.Parse in your own code and report a clear config error before constructing the logger.
Example fix
// before
logger, _ := zap.Open("file://my logs/app.log") // space breaks parsing
// after
logger, _ := zap.Open("/var/log/myapp/app.log") Defensive patterns
Strategy: validation
Validate before calling
func validSinkURL(raw string) error {
if filepath.IsAbs(raw) {
return nil
}
if _, err := url.Parse(raw); err != nil {
return fmt.Errorf("invalid sink URL %q: %w", raw, err)
}
return nil
} Try / catch
logger, err := cfg.Build()
if err != nil {
if strings.Contains(err.Error(), "can't parse") {
return fmt.Errorf("check log output URLs in config: %w", err)
}
return err
} Prevention
- Prefer plain absolute paths for file outputs
- Escape or quote special characters in URL values in config files
- Validate every Outputs entry with url.Parse during config load
When it happens
Trigger: Calling zap.Open("http://[bad::url") or Build with an Outputs entry containing unescaped characters (spaces, stray '%', unbalanced brackets), or control characters in a path derived from config/env.
Common situations: Windows-style paths with backslashes or drive letters fed as URLs; URLs with raw spaces copied from documentation; config interpolations producing 'file://%VAR%' with malformed values.
Related errors
- must start with a letter
- can't register a sink factory for empty string
- unrecognized level: %q
- %q is not a valid scheme: %v
- sink factory already registered for scheme %q
AI-assisted analysis of uber-go/zap@bbd4ecbd87 (2026-08-31).
Data as JSON: /api/errors/140ec6af61905d5b.
Report an issue: GitHub.