ipfs/kubo · error
unexpected keystore suffix %q, expected "0" or "1"
Error message
unexpected keystore suffix %q, expected "0" or "1"
What it means
This error comes from validateKeystoreSuffix in core/node/provider.go, which guards the alternating-keystore namespace scheme used by the reprovide/provider system. The upstream keystore layout alternates between two suffix directories, "0" and "1"; any other suffix means the code would be operating on a directory it does not understand. The check exists specifically so a future upstream scheme change cannot cause os.RemoveAll to delete unrelated directories. If you see it, the computed keystore suffix fell outside the two known values.
Source
Thrown at core/node/provider.go:89
keystoreDatastoreKey = datastore.NewKey("keystore")
)
// providerLog is the go-log subsystem used for provide/reprovide-related
// messages emitted from kubo's own orchestration code. It shares the
// "provider" subsystem name with boxo's provider package so users can set
// GOLOG_LOG_LEVEL=provider=<level> to control both layers at once. See
// docs/debug-guide.md for the full list of provide-related subsystems.
var providerLog = log.Logger("provider")
var errAcceleratedDHTNotReady = errors.New("AcceleratedDHTClient: routing table not ready")
// validateKeystoreSuffix rejects any suffix other than "0" or "1".
// The upstream library uses these two values as alternating namespace
// identifiers. Validating here prevents accidental deletion of unrelated
// directories via os.RemoveAll if the upstream ever changes its scheme.
func validateKeystoreSuffix(suffix string) error {
if suffix != "0" && suffix != "1" {
return fmt.Errorf("unexpected keystore suffix %q, expected \"0\" or \"1\"", suffix)
}
return nil
}
// Interval between reprovide queue monitoring checks for slow reprovide alerts.
// Used when Provide.DHT.SweepEnabled=true
const reprovideAlertPollInterval = 15 * time.Minute
// Number of consecutive polling intervals with sustained queue growth before
// triggering a slow reprovide alert (3 intervals = 45 minutes).
// Used when Provide.DHT.SweepEnabled=true
const consecutiveAlertsThreshold = 3
// DHTProvider is an interface for providing keys to a DHT swarm. It holds a
// state of keys to be advertised, and is responsible for periodically
// publishing provider records for these keys to the DHT swarm before the
// records expire.
type DHTProvider interface {View on GitHub (pinned to 329838acdf)
Solutions
- Check the version of the upstream provider library in go.mod against what kubo expects; align it (go get <lib>@<pin> + make mod_tidy).
- Inspect the keystore directories under the repo datastore path; remove or rename any directory whose suffix is not "0" or "1" (after backing up).
- Search the code path computing the suffix for a regression and fix the calculation so only "0"/"1" are produced.
- If neither suffix applies, this is a hard stop by design — do not bypass the guard; report the upstream scheme change to kubo/boxo.
Example fix
// before
suffix := fmt.Sprint(counter) // may yield "2", "3", ...
if err := validateKeystoreSuffix(suffix); err != nil { ... }
// after
suffix := "0"
if counter%2 == 1 {
suffix = "1"
}
if err := validateKeystoreSuffix(suffix); err != nil { ... } Defensive patterns
Strategy: validation
Validate before calling
func safeKeystoreSuffix(n int) (string, error) {
s := strconv.Itoa(n % 2)
if s != "0" && s != "1" {
return "", fmt.Errorf("computed suffix %q outside {0,1}", s)
}
return s, nil
} Type guard
func isValidKeystoreSuffix(s string) bool { return s == "0" || s == "1" } Prevention
- Always derive the suffix with modulo-2 of a counter, never from free-form input
- Never construct keystore paths by concatenating unvalidated strings
- Pin the upstream provider library version and review its changelog for naming-scheme changes
- Treat any "unexpected keystore suffix" log as a bug report trigger, not something to suppress
When it happens
Trigger: Calling into the keystore swap/cleanup path when the suffix variable passed to validateKeystoreSuffix is anything other than the literal "0" or "1" — typically a bug in the caller computing the suffix, or an upstream library version that changed its naming scheme.
Common situations: Running a kubo build paired with a newer/older version of the upstream provider library that altered its keystore directory naming; local manual edits or scripts that created extra keystore directories; a regression in the alternating-suffix calculation.
Related errors
- 'mounts' field is missing or not an array
- expected map for mountpoint
- no 'mountpoint' on mount
- 'name' field was missing or not a string
- 'prefix' field was missing or not a string
AI-assisted analysis of ipfs/kubo@329838acdf (2026-09-03).
Data as JSON: /api/errors/a98fbab1d4fc4d48.
Report an issue: GitHub.