{"record":{"id":"9a10ccdef30e7355","repo":"gastownhall/beads","slug":"cannot-move-unversioned-record-to-persistence-mode","errorCode":null,"errorMessage":"cannot move unversioned record to persistence mode %q","messagePattern":"cannot move unversioned record to persistence mode %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/types/types.go","lineNumber":975,"sourceCode":"func NormalizePersistenceMode(current Issue, mode PersistenceMode) (bool, bool, StorageClass, error) {\n\tif !mode.IsValid() {\n\t\treturn false, false, \"\", fmt.Errorf(\"invalid persistence mode %q\", mode)\n\t}\n\tif current.Ephemeral && current.NoHistory {\n\t\treturn false, false, \"\", fmt.Errorf(\"ephemeral and no_history are mutually exclusive\")\n\t}\n\tif !current.StorageClass.IsValid() {\n\t\treturn false, false, \"\", fmt.Errorf(\"invalid storage class %q\", current.StorageClass)\n\t}\n\twispPlane := current.Ephemeral || current.NoHistory\n\tif wispPlane && current.StorageClass != \"\" && current.StorageClass != StorageClassEphemeral {\n\t\treturn false, false, \"\", fmt.Errorf(\"storage class %q conflicts with ephemeral/no_history\", current.StorageClass)\n\t}\n\tif !wispPlane && current.StorageClass == StorageClassEphemeral {\n\t\treturn false, false, \"\", fmt.Errorf(\"storage class ephemeral requires ephemeral or no_history\")\n\t}\n\tif current.StorageClass == StorageClassUnversioned && mode != PersistenceModePersistent {\n\t\treturn false, false, \"\", fmt.Errorf(\"cannot move unversioned record to persistence mode %q\", mode)\n\t}\n\tif persistenceMode(current) == mode {\n\t\treturn current.Ephemeral, current.NoHistory, current.StorageClass, nil\n\t}\n\n\tswitch mode {\n\tcase PersistenceModePersistent:\n\t\tstorageClass := current.StorageClass\n\t\tif storageClass == StorageClassEphemeral {\n\t\t\tstorageClass = \"\"\n\t\t}\n\t\treturn false, false, storageClass, nil\n\tcase PersistenceModeEphemeral:\n\t\tstorageClass := current.StorageClass\n\t\tif storageClass == StorageClassVersioned {\n\t\t\tstorageClass = \"\"\n\t\t}\n\t\treturn true, false, storageClass, nil","sourceCodeStart":957,"sourceCodeEnd":993,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/types/types.go#L957-L993","documentation":"An unversioned record is frozen in persistent mode: once StorageClass is 'unversioned', it cannot be moved to ephemeral or no_history (wisp modes). Normalization rejects any mode other than persistent for such records, as documented — an unversioned record may remain persistent but cannot move to a wisp mode.","triggerScenarios":"Calling NormalizePersistenceMode on an Issue whose current.StorageClass == StorageClassUnversioned with mode != PersistenceModePersistent — e.g. attempting to demote it to ephemeral or no_history.","commonSituations":"Scripted cleanup jobs that sweep records into wisp modes without checking storage class; users trying to demote an unversioned issue via flags; automation assuming all records can become wisps.","solutions":["Keep the record in persistent mode, or recreate the record as a new ephemeral/no_history issue and close the unversioned one","Check StorageClass == StorageClassUnversioned before requesting a mode change and skip/branch accordingly","Change the storage class policy for the record first if the workflow truly requires wisp conversion (if supported upstream)"],"exampleFix":"// before\nNormalizePersistenceMode(issue, PersistenceModeEphemeral) // issue.StorageClass == unversioned\n// after\nif issue.StorageClass != StorageClassUnversioned {\n    NormalizePersistenceMode(issue, PersistenceModeEphemeral)\n}","handlingStrategy":"validation","validationCode":"if issue.StorageClass == StorageClassUnversioned && mode != PersistenceModePersistent {\n    return fmt.Errorf(\"issue %s is unversioned and cannot move to %s\", issue.ID, mode)\n}","typeGuard":"func canChangeMode(i Issue, m PersistenceMode) bool {\n    return i.StorageClass != StorageClassUnversioned || m == PersistenceModePersistent\n}","tryCatchPattern":"res, err := NormalizePersistenceMode(issue, mode)\nif err != nil && strings.Contains(err.Error(), \"cannot move unversioned record\") {\n    // keep persistent or recreate as new wisp issue\n}","preventionTips":["Filter out unversioned records in any bulk demotion to wisp modes","Check storage class before issuing persistence-mode updates","Document that unversioned records are mode-frozen in persistent"],"tags":["persistence","unversioned","state-conflict"],"backgroundTag":"unversioned-mode-transition-forbidden","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}