m1k1o/neko · error
unknown resource: %s
Error message
unknown resource: %s
What it means
In the legacy websocket-to-backend translation layer, the ADMIN_LOCK event carries a `resource` field that must be one of a fixed set of values the shim knows how to map onto new backend room settings. When `request.Resource` matches none of the handled cases ('login', 'control', 'file_transfer'), wsToBackend returns fmt.Errorf("unknown resource: %s", request.Resource) instead of issuing the /api/room/settings call.
Source
Thrown at server/internal/http/legacy/wstobackend.go:289
request := &oldMessage.AdminLock{}
err := json.Unmarshal(msg, request)
if err != nil {
return err
}
data := map[string]any{}
switch request.Resource {
case "login":
data["locked_logins"] = true
case "control":
data["locked_controls"] = true
case "file_transfer":
data["plugins"] = map[string]any{
"filetransfer.enabled": false,
}
default:
return fmt.Errorf("unknown resource: %s", request.Resource)
}
return s.apiReq(http.MethodPost, "/api/room/settings", data, nil)
case oldEvent.ADMIN_UNLOCK:
request := &oldMessage.AdminLock{}
err := json.Unmarshal(msg, request)
if err != nil {
return err
}
data := map[string]any{}
switch request.Resource {
case "login":
data["locked_logins"] = false
case "control":
data["locked_controls"] = falseView on GitHub (pinned to b0f01cedea)
Solutions
- Log the received request.Resource value and confirm which string the legacy client is sending
- Map the value to one of the supported resources ('login', 'control', 'file_transfer') on the client side, or fix the client typo
- Extend the switch in wsToBackend ADMIN_LOCK handling with a new case that translates the resource into the corresponding /api/room/settings key
- Update the legacy shim and clients to the same protocol version
Example fix
// before (client payload)
{"event":"admin_lock","resource":"filetransfer"}
// after
{"event":"admin_lock","resource":"file_transfer"} Defensive patterns
Strategy: validation
Validate before calling
func validateLockResource(resource string) error {
switch resource {
case "login", "control", "file_transfer":
return nil
default:
return fmt.Errorf("unsupported lock resource %q: must be login, control, or file_transfer", resource)
}
} Type guard
func isKnownLockResource(r string) bool {
switch r {
case "login", "control", "file_transfer":
return true
}
return false
} Try / catch
if err := validateLockResource(req.Resource); err != nil {
log.Printf("skipping admin_lock: %v", err)
return nil // or surface a client-facing 'unsupported resource' message
} Prevention
- Validate the resource string on the client before sending admin_lock frames
- Keep a shared constant list of supported resources between client and shim
- Add a case or explicit rejection in tests for every resource the old protocol defines
When it happens
Trigger: A legacy client sends an admin lock websocket message whose `resource` field is a string other than "login", "control", or "file_transfer" — e.g. a typo like "filetransfer", an empty string, or a resource added in the old protocol after this shim was written.
Common situations: Running an old frontline/admin client against a newer backend through the legacy shim; hand-crafted websocket messages from scripts or tests; version drift where the old protocol gained a new lockable resource that the shim's switch statement was never extended to translate.
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
- unknown event type: %s
- listener cannot be nil
- cannot access clipboard
- is not the host
- ErrIsNotAllowedToHost
AI-assisted analysis of m1k1o/neko@b0f01cedea (2026-09-01).
Data as JSON: /api/errors/16a1f7f8d05925ea.
Report an issue: GitHub.