uber-go/zap · error

fragments not allowed with file URLs: got %v

Error message

fragments not allowed with file URLs: got %v

What it means

newFileSinkFromURL rejects file:// URLs containing a fragment (the part after '#'). Fragments are meaningless for filesystem paths, so zap refuses the URL to prevent silently writing to a truncated path.

Source

Thrown at sink.go:135

}

// 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 3986
// (https://tools.ietf.org/html/rfc3983#section-3.1), and must not already
// have a factory registered. Zap automatically registers a factory for the
// "file" scheme.
func RegisterSink(scheme string, factory func(*url.URL) (Sink, error)) error {
	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":

View on GitHub (pinned to bbd4ecbd87)

Solutions

  1. Strip the '#fragment' portion from the file URL.
  2. Use a plain absolute path instead of a file:// URL.
  3. URL-encode or sanitize destination values before inserting them into logging config.

Example fix

// before
zap.Open("file:///var/log/app.log#startup")
// after
zap.Open("file:///var/log/app.log")
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(dest)
if err == nil && u.Scheme == "file" && u.Fragment != "" {
    return fmt.Errorf("file URL must not contain a fragment: %s", dest)
}

Try / catch

if _, err := zap.Open(dest); err != nil {
    if strings.Contains(err.Error(), "fragments not allowed") {
        return fmt.Errorf("remove '#...' from file URL %q", dest)
    }
    return err
}

Prevention

When it happens

Trigger: Passing a destination like file:///var/log/app.log#section to zap.Open; URLs copied from HTML pages or anchors appended to log destinations.

Common situations: Copy-pasting URLs that include in-page anchors; template engines injecting fragments; linking configs that include bookmark suffixes.

Related errors


AI-assisted analysis of uber-go/zap@bbd4ecbd87 (2026-08-31). Data as JSON: /api/errors/e6d466277652dc4d. Report an issue: GitHub.