{"record":{"id":"5876a2d3a2c04b87","repo":"ipfs/kubo","slug":"provide-dht-offlinedelay-must-be-non-negative-got","errorCode":null,"errorMessage":"Provide.DHT.OfflineDelay must be non-negative, got %v","messagePattern":"Provide\\.DHT\\.OfflineDelay must be non-negative, got (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"config/provide.go","lineNumber":279,"sourceCode":"\t\tconns := cfg.DHT.MaxProvideConnsPerWorker.WithDefault(DefaultProvideDHTMaxProvideConnsPerWorker)\n\t\tif conns <= 0 {\n\t\t\treturn fmt.Errorf(\"Provide.DHT.MaxProvideConnsPerWorker must be positive, got %d\", conns)\n\t\t}\n\t}\n\n\t// Validate KeystoreBatchSize\n\tif !cfg.DHT.KeystoreBatchSize.IsDefault() {\n\t\tbatchSize := cfg.DHT.KeystoreBatchSize.WithDefault(DefaultProvideDHTKeystoreBatchSize)\n\t\tif batchSize <= 0 {\n\t\t\treturn fmt.Errorf(\"Provide.DHT.KeystoreBatchSize must be positive, got %d\", batchSize)\n\t\t}\n\t}\n\n\t// Validate OfflineDelay\n\tif !cfg.DHT.OfflineDelay.IsDefault() {\n\t\tdelay := cfg.DHT.OfflineDelay.WithDefault(DefaultProvideDHTOfflineDelay)\n\t\tif delay < 0 {\n\t\t\treturn fmt.Errorf(\"Provide.DHT.OfflineDelay must be non-negative, got %v\", delay)\n\t\t}\n\t}\n\n\t// Validate SendProviderRecordTimeout\n\tif !cfg.DHT.SendProviderRecordTimeout.IsDefault() {\n\t\ttimeout := cfg.DHT.SendProviderRecordTimeout.WithDefault(DefaultProvideDHTSendProviderRecordTimeout)\n\t\tif timeout <= 0 {\n\t\t\treturn fmt.Errorf(\"Provide.DHT.SendProviderRecordTimeout must be positive, got %v\", timeout)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// ShouldProvideForStrategy determines if content should be provided based on the provide strategy\n// and content characteristics (pinned status, root status, MFS status).\nfunc ShouldProvideForStrategy(strategy ProvideStrategy, isPinned bool, isPinnedRoot bool, isMFS bool) bool {\n\tif strategy&ProvideStrategyAll != 0 {","sourceCodeStart":261,"sourceCodeEnd":297,"githubUrl":"https://github.com/ipfs/kubo/blob/329838acdfafae224582930457efe80aa217afc0/config/provide.go#L261-L297","documentation":"ValidateProvideConfig rejects Provide.DHT.OfflineDelay when it is explicitly set but resolves to a negative duration. OfflineDelay controls how long the node waits after going offline before treating the provider keystore as stale, so negative values are meaningless. Validation runs during node setup and aborts startup.","triggerScenarios":"Writing a negative duration string such as \"-5s\" or \"-1h\" to Provide.DHT.OfflineDelay (e.g. `ipfs config --json Provide.DHT.OfflineDelay '-5s'`) then starting the node or invoking IPFS construction, which calls ValidateProvideConfig.","commonSituations":"Attempting to 'disable' the delay with a negative sentinel, arithmetic generating negative durations, or hand-editing config.json with a typo before the duration value.","solutions":["Set Provide.DHT.OfflineDelay to a non-negative duration (e.g. \"0s\" or \"10m\").","Delete the Provide.DHT.OfflineDelay key so the default DefaultProvideDHTOfflineDelay is used.","Inspect the value with `ipfs config Provide.DHT.OfflineDelay` and correct the sign."],"exampleFix":"// before (config.json)\n\"Provide\": { \"DHT\": { \"OfflineDelay\": \"-5m\" } }\n// after\n\"Provide\": { \"DHT\": { \"OfflineDelay\": \"5m\" } }","handlingStrategy":"validation","validationCode":"d, err := time.ParseDuration(raw)\nif err != nil || d < 0 {\n    return fmt.Errorf(\"OfflineDelay must be a non-negative duration, got %q\", raw)\n}","typeGuard":null,"tryCatchPattern":"if err := config.ValidateProvideConfig(cfg); err != nil { log.Fatalf(\"invalid provide config: %v\", err) }","preventionTips":["Use time.Duration string forms like \"10m\"; never prefix with '-'","Use 0s explicitly if you want no delay","Validate durations before writing them into the config"],"tags":["config","go","validation","duration"],"backgroundTag":"invalid-config-value","analyzedSha":"329838acdfafae224582930457efe80aa217afc0","analyzedAt":"2026-09-03T18:30:52.135Z","contentChangedAt":"2026-09-03T18:30:52.135Z","schemaVersion":2},"datasetVersion":"2026-09-11T00:17:11.886Z"}