gastownhall/beads · error
invalid persistence mode %q
Error message
invalid persistence mode %q
What it means
NormalizePersistenceMode validates the requested PersistenceMode against the known set (persistent, ephemeral, no_history). An unrecognized string mode is rejected before any state change. This guards against typos in flags or config.
Source
Thrown at internal/types/types.go:959
PersistenceModeEphemeral,
PersistenceModeNoHistory,
}
// IsValid reports whether a persistence mode is a known explicit value.
// Empty is invalid because it would be indistinguishable from an omitted mode.
func (m PersistenceMode) IsValid() bool {
return slices.Contains(validPersistenceModes, m)
}
// NormalizePersistenceMode maps a requested mode from current to its exact
// persistence fields without mutating an issue. The returned values are
// Ephemeral, NoHistory, and StorageClass, respectively. Plane and retention
// changes preserve the create-selected class. Promotion clears an explicit
// ephemeral class marker to select normalized versioned storage. An
// unversioned record may remain persistent but cannot move to a wisp mode.
func NormalizePersistenceMode(current Issue, mode PersistenceMode) (bool, bool, StorageClass, error) {
if !mode.IsValid() {
return false, false, "", fmt.Errorf("invalid persistence mode %q", mode)
}
if current.Ephemeral && current.NoHistory {
return false, false, "", fmt.Errorf("ephemeral and no_history are mutually exclusive")
}
if !current.StorageClass.IsValid() {
return false, false, "", fmt.Errorf("invalid storage class %q", current.StorageClass)
}
wispPlane := current.Ephemeral || current.NoHistory
if wispPlane && current.StorageClass != "" && current.StorageClass != StorageClassEphemeral {
return false, false, "", fmt.Errorf("storage class %q conflicts with ephemeral/no_history", current.StorageClass)
}
if !wispPlane && current.StorageClass == StorageClassEphemeral {
return false, false, "", fmt.Errorf("storage class ephemeral requires ephemeral or no_history")
}
if current.StorageClass == StorageClassUnversioned && mode != PersistenceModePersistent {
return false, false, "", fmt.Errorf("cannot move unversioned record to persistence mode %q", mode)
}
if persistenceMode(current) == mode {View on GitHub (pinned to 71377f2769)
Solutions
- Use one of the exported PersistenceMode constants instead of a raw string
- Check the accepted values via PersistenceMode's IsValid/parse helpers and correct the spelling
- Upgrade/align code after a mode rename in a newer library version
Example fix
// before
NormalizePersistenceMode(issue, PersistenceMode("persistant"))
// after
NormalizePersistenceMode(issue, PersistenceModePersistent) Defensive patterns
Strategy: validation
Validate before calling
mode := PersistenceMode(input)
if !mode.IsValid() {
return fmt.Errorf("%q is not a valid persistence mode", input)
} Type guard
func validPersistenceMode(s string) (PersistenceMode, bool) {
m := PersistenceMode(s)
return m, m.IsValid()
} Try / catch
res, err := NormalizePersistenceMode(issue, mode)
if err != nil && strings.Contains(err.Error(), "invalid persistence mode") {
// surface valid options to the user
} Prevention
- Always use exported PersistenceMode constants, never raw strings
- Validate flag values with IsValid() before calling library functions
- Grep configs for known typos after upgrading versions
When it happens
Trigger: Calling NormalizePersistenceMode(current Issue, mode) with a mode value that fails mode.IsValid() — e.g. mode "persistant" (typo), "", or an arbitrary string cast to PersistenceMode.
Common situations: Typo in a --persistence flag value; old config using a renamed mode value; programmatic code passing a raw string without using the PersistenceMode constants.
Related errors
- server: NewDoltServer: doltBinExec is required
- server: NewDoltServer: rootDir is required
- server: NewDoltServer: configPath is required
- ErrPrefixMismatch
- persist sync.remote to config.yaml: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/305aab2ba5624fe2.
Report an issue: GitHub.