{"record":{"id":"c4e60377a5d673d7","repo":"ipfs/kubo","slug":"invalid-provide-strategy-empty-token-in-q","errorCode":null,"errorMessage":"invalid provide strategy: empty token in %q","messagePattern":"invalid provide strategy: empty token in %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"config/provide.go","lineNumber":151,"sourceCode":"\t// When enabled, the provider persists its reprovide cycle state and provide queue to the datastore,\n\t// and restores them on restart. When disabled, the provider starts fresh on each restart.\n\t// Default: true\n\tResumeEnabled Flag `json:\",omitempty\"`\n}\n\nfunc ParseProvideStrategy(s string) (ProvideStrategy, error) {\n\tvar strategy ProvideStrategy\n\tfor part := range strings.SplitSeq(s, \"+\") {\n\t\tswitch part {\n\t\tcase \"all\", \"flat\":\n\t\t\tstrategy |= ProvideStrategyAll\n\t\tcase \"\":\n\t\t\t// empty string (default config) maps to \"all\",\n\t\t\t// but empty tokens from splitting (e.g. \"pinned+\") are invalid\n\t\t\tif s == \"\" {\n\t\t\t\tstrategy |= ProvideStrategyAll\n\t\t\t} else {\n\t\t\t\treturn 0, fmt.Errorf(\"invalid provide strategy: empty token in %q\", s)\n\t\t\t}\n\t\tcase \"pinned\":\n\t\t\tstrategy |= ProvideStrategyPinned\n\t\tcase \"roots\":\n\t\t\tstrategy |= ProvideStrategyRoots\n\t\tcase \"mfs\":\n\t\t\tstrategy |= ProvideStrategyMFS\n\t\tcase \"unique\":\n\t\t\tstrategy |= ProvideStrategyUnique\n\t\tcase \"entities\":\n\t\t\tstrategy |= ProvideStrategyEntities | ProvideStrategyUnique\n\t\tdefault:\n\t\t\treturn 0, fmt.Errorf(\"unknown provide strategy token: %q in %q\", part, s)\n\t\t}\n\t}\n\t// \"all\" provides every block and cannot be combined with selective strategies\n\tif strategy&ProvideStrategyAll != 0 && strategy != ProvideStrategyAll {\n\t\treturn 0, fmt.Errorf(\"\\\"all\\\" strategy cannot be combined with other strategies in %q\", s)","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/ipfs/kubo/blob/329838acdfafae224582930457efe80aa217afc0/config/provide.go#L133-L169","documentation":"ParseProvideStrategy parses Provide.Strategy, a '+'-separated token list (e.g. 'pinned+mfs'). An empty string is accepted (maps to 'all'), but an empty token produced by splitting — from a leading, trailing, or doubled '+' such as 'pinned+' or 'pinned++mfs' — is invalid and returns this error.","triggerScenarios":"Setting Provide.Strategy to a value with a stray '+' separator: 'pinned+', '+mfs', 'pinned++mfs', or 'all+' — then starting the daemon or calling ParseProvideStrategy/ValidateProvideConfig.","commonSituations":"Scripted config assembly that appends '+' between tokens unconditionally leaving a trailing separator; hand-editing config.json and leaving a dangling plus; sed/awk joins that produce double separators.","solutions":["Remove stray '+' characters so the strategy contains no empty tokens: ipfs config Provide.Strategy pinned+mfs","Reset to default by setting an empty string: ipfs config Provide.Strategy '' (empty means 'all')","In code, sanitize before parsing: strings.Trim(s, \"+\") and collapse '+'-runs, or reject tokens after strings.Split(s, \"+\") that are empty when s != \"\""],"exampleFix":"// before\nipfs config Provide.Strategy 'pinned+'\n// after\nipfs config Provide.Strategy 'pinned'","handlingStrategy":"validation","validationCode":"if s != \"\" && (strings.HasPrefix(s, \"+\") || strings.HasSuffix(s, \"+\") || strings.Contains(s, \"++\")) {\n\treturn fmt.Errorf(\"empty token in strategy %q\", s)\n}\nif _, err := config.ParseProvideStrategy(s); err != nil { return err }","typeGuard":"func hasNoEmptyTokens(s string) bool {\n\tif s == \"\" { return true }\n\tfor part := range strings.SplitSeq(s, \"+\") {\n\t\tif part == \"\" { return false }\n\t}\n\treturn true\n}","tryCatchPattern":"strategy, err := config.ParseProvideStrategy(s)\nif err != nil {\n\treturn fmt.Errorf(\"Provide.Strategy %q invalid: %w\", s, err)\n}","preventionTips":["Join tokens with strings.Join(tokens, \"+\") instead of manual concatenation","Call ParseProvideStrategy at config-write time, not only at startup","Remember empty string is valid (means 'all'); only split-produced empty tokens are errors"],"tags":["config","provide","parsing","dht"],"backgroundTag":"invalid-enum-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"}