{"record":{"id":"6d318f1a1ac721ef","repo":"ipfs/kubo","slug":"provider-unique-requires-pinned-and-or-mfs","errorCode":null,"errorMessage":"provider: +unique requires pinned and/or mfs","messagePattern":"provider: \\+unique requires pinned and/or mfs","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/node/provider.go","lineNumber":1377,"sourceCode":"\t\t\tcase basePinned && baseMFS:\n\t\t\t\t// MFS first: walk MFS (locality-filtered), then pinned.\n\t\t\t\t// NewConcatProvider (not NewPrioritizedProvider) because\n\t\t\t\t// the shared bloom tracker already guarantees each CID\n\t\t\t\t// is emitted at most once -- no need for a second dedup\n\t\t\t\t// layer. NewBufferedProvider decouples the pinned\n\t\t\t\t// provider so the pinner lock is released promptly.\n\t\t\t\tinner = provider.NewConcatProvider(\n\t\t\t\t\tmakeMFSProv(in.MFSRoot, in.Blockstore, tracker),\n\t\t\t\t\tprovider.NewBufferedProvider(\n\t\t\t\t\t\tmakePinProv(in.Pinner, in.Blockstore, tracker)),\n\t\t\t\t)\n\t\t\tcase basePinned:\n\t\t\t\tinner = provider.NewBufferedProvider(\n\t\t\t\t\tmakePinProv(in.Pinner, in.Blockstore, tracker))\n\t\t\tcase baseMFS:\n\t\t\t\tinner = makeMFSProv(in.MFSRoot, in.Blockstore, tracker)\n\t\t\tdefault:\n\t\t\t\treturn nil, fmt.Errorf(\"provider: +unique requires pinned and/or mfs\")\n\t\t\t}\n\n\t\t\t// wrap inner channel to persist bloom count on successful close\n\t\t\tinnerCh, err := inner(ctx)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tch := make(chan cid.Cid)\n\t\t\tgo func() {\n\t\t\t\tdefer func() {\n\t\t\t\t\tif ctx.Err() == nil {\n\t\t\t\t\t\tpersistUniqueCount(ds, tracker.Count())\n\t\t\t\t\t}\n\t\t\t\t\tproviderLog.Infow(\"unique reprovide cycle finished\",\n\t\t\t\t\t\t\"providedCIDs\", tracker.Count(),\n\t\t\t\t\t\t\"skippedBranches\", tracker.Deduplicated())\n\t\t\t\t\tclose(ch)","sourceCodeStart":1359,"sourceCodeEnd":1395,"githubUrl":"https://github.com/ipfs/kubo/blob/329838acdfafae224582930457efe80aa217afc0/core/node/provider.go#L1359-L1395","documentation":"A configuration error raised during a '+unique' reprovide cycle: the Provide.Strategy includes the '+unique' modifier but neither the 'pinned' nor the 'mfs' base strategy is enabled. '+unique' is a modifier that deduplicates walking; it needs at least one base source of CIDs to walk. The cycle is aborted before any providing happens.","triggerScenarios":"Setting Provide.Strategy to something like 'unique' or 'entities+unique' without 'pinned' and/or 'mfs' (valid combos are pinned+mfs+unique etc.), then a reprovide cycle runs createKeyProvider and hits the default switch case.","commonSituations":"Hand-editing Provide.Strategy in the kubo config or following outdated docs/flags that list '+unique' without a base strategy.","solutions":["Set Provide.Strategy to include a base: e.g. 'pinned+mfs+unique' or 'pinned+unique' via 'ipfs config Provide.Strategy pinned+mfs+unique'","Run 'ipfs config show' to verify the current strategy string","Restart the daemon after fixing the config"],"exampleFix":"// before (config.json)\n\"Provide\": { \"Strategy\": \"unique\" }\n// after\n\"Provide\": { \"Strategy\": \"pinned+mfs+unique\" }","handlingStrategy":"validation","validationCode":"// validate strategy before writing config:\n// go run: config.ParseProvideStrategy(\"pinned+mfs+unique\") must not error,\n// and +unique must be combined with pinned and/or mfs.\nstrategy := \"pinned+mfs+unique\" // not \"unique\" alone","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always combine '+unique' with a base: 'pinned', 'mfs', or both","Validate with 'ipfs config Provide.Strategy' before restart","Check docs/config.md for the accepted strategy grammar"],"tags":["config","provider","strategy","unique","reprovide"],"backgroundTag":"invalid-provide-strategy","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"}