{"record":{"id":"830337af0f5a1124","repo":"uber-go/zap","slug":"sink-factory-already-registered-for-scheme-q","errorCode":null,"errorMessage":"sink factory already registered for scheme %q","messagePattern":"sink factory already registered for scheme %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sink.go","lineNumber":87,"sourceCode":"\t// Infallible operation: the registry is empty, so we can't have a conflict.\n\t_ = sr.RegisterSink(schemeFile, sr.newFileSinkFromURL)\n\treturn sr\n}\n\n// RegisterSink registers the given factory for the specific scheme.\nfunc (sr *sinkRegistry) RegisterSink(scheme string, factory func(*url.URL) (Sink, error)) error {\n\tsr.mu.Lock()\n\tdefer sr.mu.Unlock()\n\n\tif scheme == \"\" {\n\t\treturn errors.New(\"can't register a sink factory for empty string\")\n\t}\n\tnormalized, err := normalizeScheme(scheme)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"%q is not a valid scheme: %v\", scheme, err)\n\t}\n\tif _, ok := sr.factories[normalized]; ok {\n\t\treturn fmt.Errorf(\"sink factory already registered for scheme %q\", normalized)\n\t}\n\tsr.factories[normalized] = factory\n\treturn nil\n}\n\nfunc (sr *sinkRegistry) newSink(rawURL string) (Sink, error) {\n\t// URL parsing doesn't work well for Windows paths such as `c:\\log.txt`, as scheme is set to\n\t// the drive, and path is unset unless `c:/log.txt` is used.\n\t// To avoid Windows-specific URL handling, we instead check IsAbs to open as a file.\n\t// filepath.IsAbs is OS-specific, so IsAbs('c:/log.txt') is false outside of Windows.\n\tif filepath.IsAbs(rawURL) {\n\t\treturn sr.newFileSinkFromPath(rawURL)\n\t}\n\n\tu, err := url.Parse(rawURL)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"can't parse %q as a URL: %v\", rawURL, err)\n\t}","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/uber-go/zap/blob/bbd4ecbd8760678fdbac94c93d9aca8069c83b2f/sink.go#L69-L105","documentation":"RegisterSink stores one factory per normalized scheme; registering a second factory for the same scheme returns this error. Zap intentionally forbids overwriting existing sink factories to avoid silently changing behavior of already-constructed loggers.","triggerScenarios":"Calling zap.RegisterSink(\"kafka\", f) twice — typically once in package init() and once in main, or across two imported packages that both register the same scheme, or in tests that re-register per test case.","commonSituations":"Multiple libraries in the dependency graph each calling RegisterSink for their own scheme with the same name; running package tests where init registration runs per binary but manual registration is repeated; hot-reloading code that re-registers sinks.","solutions":["Register each scheme exactly once, e.g. with sync.Once or in a single init() function.","Check for the error and treat it as benign if the identical factory is already registered (skip re-registration).","Use a unique scheme name for your custom sink (e.g. 'myco-kafka' instead of 'kafka')."],"exampleFix":"// before\nfunc init() { zap.RegisterSink(\"kafka\", newKafkaSink) }\nfunc main() { zap.RegisterSink(\"kafka\", newKafkaSink) // panics/error }\n// after\nvar registerOnce sync.Once\nfunc registerSink() {\n    registerOnce.Do(func() { _ = zap.RegisterSink(\"kafka\", newKafkaSink) })\n}","handlingStrategy":"try-catch","validationCode":"var registered sync.Map\nfunc ensureRegistered(scheme string, f func(*url.URL) (zap.Sink, error)) error {\n    if _, dup := registered.LoadOrStore(scheme, true); dup {\n        return nil\n    }\n    return zap.RegisterSink(scheme, f)\n}","typeGuard":null,"tryCatchPattern":"if err := zap.RegisterSink(scheme, factory); err != nil {\n    if strings.Contains(err.Error(), \"already registered\") {\n        return nil // idempotent registration\n    }\n    return err\n}","preventionTips":["Register custom sinks once with sync.Once or in a single init()","Give your sink a unique scheme namespaced to your organization","In tests, register in TestMain rather than each test function"],"tags":["zap","sink","registry","duplicate-registration"],"backgroundTag":"duplicate-registration","analyzedSha":"bbd4ecbd8760678fdbac94c93d9aca8069c83b2f","analyzedAt":"2026-08-31T13:01:40.228Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}