kopia/kopia · error
Invalid access level
Error message
Invalid access level: %v
What it means
AccessLevel.MarshalJSON looks up the level in accessLevelToString; if the AccessLevel value has no registered string representation, marshaling fails with "Invalid access level". This guards against out-of-range or unregistered enum values being serialized into ACL JSON.
Solutions
- Use only the defined AccessLevel constants (e.g. kopiaacl.Read/Write/FullAccess-style exported levels) rather than raw integers.
- Validate the access level before marshaling: keep a map of valid values and check membership.
- Re-generate the ACL with a supported level via the kopia ACL commands/API.
- If data came from another version, migrate the stored ACL to current enum values.
Example fix
// before
lvl := acl.AccessLevel(7)
data, err := json.Marshal(lvl) // "Invalid access level: 7"
// after
lvl := acl.AccessLevelRead // use a defined constant
if _, ok := acl.AccessLevelToString[lvl]; !ok {
return fmt.Errorf("unsupported access level %v", lvl)
}
data, err := json.Marshal(lvl) Defensive patterns
Strategy: validation
Validate before calling
func validAccessLevel(l acl.AccessLevel, known map[acl.AccessLevel]string) bool {
_, ok := known[l]
return ok
}
// check before json.Marshal(lvl) Type guard
func isKnownAccessLevel(l acl.AccessLevel, known map[acl.AccessLevel]string) bool {
_, ok := known[l]
return ok
} Try / catch
data, err := json.Marshal(aclEntry)
if err != nil && strings.Contains(err.Error(), "Invalid access level") {
return fmt.Errorf("access level %v not supported; use a defined constant: %w", lvl, err)
} Prevention
- Only use exported AccessLevel constants; never cast raw ints/strings to AccessLevel.
- Validate ACL JSON input against known levels before storing it.
- Migrate ACL data when upgrading across versions that changed the enum.
When it happens
Trigger: Marshaling an AccessLevel that was constructed from an unknown integer/string — e.g. AccessLevel(99) via an unchecked conversion, a value deserialized from corrupt or foreign ACL JSON, or a zero-value AccessLevel when the enum starts at 1 and no default is registered.
Common situations: Hand-editing ACL JSON with an unsupported access level string/number; upgrading/downgrading kopia so an old ACL references a level no longer defined; programmatically building ACLs with an invalid level constant.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- valid access level must be specified
- access level ' ' is unsupported
- ACL entry for a given user and target already exists
- ACL target must have a
- error adding ACL entry
AI-assisted analysis of kopia/kopia@82495e54b5 (2026-09-07).
Data as JSON: /api/errors/a462e51bd414855e.
Report an issue: GitHub.
Appendix: source
Thrown at internal/acl/access_level.go:49
for k, v := range accessLevelToString {
stringToAccessLevel[v] = k
}
}
func (a AccessLevel) String() string {
s, ok := accessLevelToString[a]
if !ok {
return strconv.Itoa(int(a))
}
return s
}
// MarshalJSON implements json.Marshaler.
func (a AccessLevel) MarshalJSON() ([]byte, error) {
j, ok := accessLevelToString[a]
if !ok {
return nil, errors.Errorf("Invalid access level: %v", a)
}
//nolint:wrapcheck
return json.Marshal(j)
}
// UnmarshalJSON implements json.Unmarshaler.
func (a *AccessLevel) UnmarshalJSON(b []byte) error {
var s string
if err := json.Unmarshal(b, &s); err != nil {
return errors.Wrap(err, "error unmarshaling access level")
}
*a = stringToAccessLevel[s]
return nil
}View on GitHub (pinned to 82495e54b5)