{"record":{"id":"a1f4f89e56c239d8","repo":"gastownhall/beads","slug":"invalid-storage-class-q-must-be-s","errorCode":null,"errorMessage":"invalid storage class %q (must be %s)","messagePattern":"invalid storage class %q \\(must be (.+?)\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/types/types.go","lineNumber":1032,"sourceCode":"func (s StorageClass) IsValid() bool {\n\tif s == \"\" {\n\t\treturn true\n\t}\n\treturn slices.Contains(validStorageClasses, s)\n}\n\n// ValidStorageClassNames enumerates the accepted values for error messages.\nfunc ValidStorageClassNames() string {\n\treturn joinNamesWithOr(validStorageClasses)\n}\n\n// ParseStorageClass validates a user-supplied storage-class value (flag or\n// config). Empty is rejected here — callers that allow \"unset\" check for\n// empty before parsing.\nfunc ParseStorageClass(v string) (StorageClass, error) {\n\ts := StorageClass(v)\n\tif s == \"\" || !s.IsValid() {\n\t\treturn \"\", fmt.Errorf(\"invalid storage class %q (must be %s)\", v, ValidStorageClassNames())\n\t}\n\treturn s, nil\n}\n\n// Normalize maps the explicit versioned spelling to unset: the two are\n// semantically identical and the marker is omitted when versioned in storage\n// cells and serialized records alike. Both insert stacks call this so\n// the database never persists the literal \"versioned\".\nfunc (s StorageClass) Normalize() StorageClass {\n\tif s == StorageClassVersioned {\n\t\treturn \"\"\n\t}\n\treturn s\n}\n\n// EffectiveStorageClass resolves the record's class: an explicit declaration\n// wins; otherwise wisp-plane records (Ephemeral or NoHistory) are ephemeral\n// and everything else is versioned.","sourceCodeStart":1014,"sourceCodeEnd":1050,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/types/types.go#L1014-L1050","documentation":"ParseStorageClass validates a user-supplied storage-class value from a flag or config. Empty and unrecognized values are rejected, and the error lists the valid names via ValidStorageClassNames() so the user can self-correct. Callers that allow 'unset' must check for empty before calling.","triggerScenarios":"Calling ParseStorageClass(\"\") or with any string not in validStorageClasses — e.g. --storage-class=ephemaral, 'ssd', or a value from an old config schema.","commonSituations":"Typos on the command line; copying flag values from another tool with different class names; stale config written before class names were renamed.","solutions":["Use one of the names printed in the error message (see ValidStorageClassNames())","For optional values, skip parsing when the input is empty — ParseStorageClass rejects empty by design","Route all user input through ParseStorageClass and fix at the config/flag source, never cast raw strings to StorageClass"],"exampleFix":"// before\nsc, err := ParseStorageClass(\"ephemaral\") // typo\n// after\nsc, err := ParseStorageClass(\"ephemeral\")","handlingStrategy":"validation","validationCode":"if v == \"\" {\n    return nil // unset is allowed by this caller\n}\nif _, err := ParseStorageClass(v); err != nil {\n    return fmt.Errorf(\"--storage-class: %v\", err)\n}","typeGuard":"func isKnownStorageClass(s string) bool {\n    return StorageClass(s).IsValid()\n}","tryCatchPattern":"sc, err := ParseStorageClass(v)\nif err != nil {\n    return fmt.Errorf(\"bad --storage-class %q: %w\", v, err) // error already lists valid values\n}","preventionTips":["Check for empty input before calling ParseStorageClass if 'unset' is allowed","Copy class names only from ValidStorageClassNames() output","Validate config files at load time with ParseStorageClass to fail fast"],"tags":["storage-class","config","validation"],"backgroundTag":"invalid-storage-class","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}