{"record":{"id":"db0375735d8f38b5","repo":"uber-go/zap","slug":"ports-not-allowed-with-file-urls-got-v","errorCode":null,"errorMessage":"ports not allowed with file URLs: got %v","messagePattern":"ports not allowed with file URLs: got (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sink.go","lineNumber":142,"sourceCode":"// have a factory registered. Zap automatically registers a factory for the\n// \"file\" scheme.\nfunc RegisterSink(scheme string, factory func(*url.URL) (Sink, error)) error {\n\treturn _sinkRegistry.RegisterSink(scheme, factory)\n}\n\nfunc (sr *sinkRegistry) newFileSinkFromURL(u *url.URL) (Sink, error) {\n\tif u.User != nil {\n\t\treturn nil, fmt.Errorf(\"user and password not allowed with file URLs: got %v\", u)\n\t}\n\tif u.Fragment != \"\" {\n\t\treturn nil, fmt.Errorf(\"fragments not allowed with file URLs: got %v\", u)\n\t}\n\tif u.RawQuery != \"\" {\n\t\treturn nil, fmt.Errorf(\"query parameters not allowed with file URLs: got %v\", u)\n\t}\n\t// Error messages are better if we check hostname and port separately.\n\tif u.Port() != \"\" {\n\t\treturn nil, fmt.Errorf(\"ports not allowed with file URLs: got %v\", u)\n\t}\n\tif hn := u.Hostname(); hn != \"\" && hn != \"localhost\" {\n\t\treturn nil, fmt.Errorf(\"file URLs must leave host empty or use localhost: got %v\", u)\n\t}\n\n\treturn sr.newFileSinkFromPath(u.Path)\n}\n\nfunc (sr *sinkRegistry) newFileSinkFromPath(path string) (Sink, error) {\n\tswitch path {\n\tcase \"stdout\":\n\t\treturn nopCloserSink{os.Stdout}, nil\n\tcase \"stderr\":\n\t\treturn nopCloserSink{os.Stderr}, nil\n\t}\n\treturn sr.openFile(path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0o666)\n}\n","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/uber-go/zap/blob/bbd4ecbd8760678fdbac94c93d9aca8069c83b2f/sink.go#L124-L160","documentation":"newFileSinkFromURL rejects file:// URLs containing a port. Ports only apply to network endpoints; a port in a file URL signals a confused destination string, so zap rejects it with a targeted message.","triggerScenarios":"Passing file://localhost:8080/var/log/app.log or file://:5432/path to zap.Open; swapping the scheme of a network sink URL to file:// while keeping host:port.","commonSituations":"Environment-driven sink URLs where LOG_URL like tcp://host:port is re-schemed to file://; templated configs reusing the same host:port pair across sinks.","solutions":["Remove the :port component; file URLs must have an empty host or only 'localhost'.","If you need a network destination, keep the original scheme (tcp/udp or a registered custom sink) rather than file://.","Use a plain absolute path for file logging."],"exampleFix":"// before\nzap.Open(\"file://localhost:8080/var/log/app.log\")\n// after\nzap.Open(\"file:///var/log/app.log\")","handlingStrategy":"validation","validationCode":"u, err := url.Parse(dest)\nif err == nil && u.Scheme == \"file\" && u.Port() != \"\" {\n    return fmt.Errorf(\"file URL must not contain a port: %s\", dest)\n}","typeGuard":null,"tryCatchPattern":"if _, err := zap.Open(dest); err != nil {\n    if strings.Contains(err.Error(), \"ports not allowed\") {\n        return fmt.Errorf(\"remove host:port from file URL %q\", dest)\n    }\n    return err\n}","preventionTips":["Use file:///path with an empty host for local files","Never re-scheme network URLs (host:port) to file://","Separate network sink config from file sink config in templates"],"tags":["zap","file-sink","url","validation"],"backgroundTag":"invalid-file-url","analyzedSha":"bbd4ecbd8760678fdbac94c93d9aca8069c83b2f","analyzedAt":"2026-08-31T13:01:40.228Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}