{"record":{"id":"4034863f0fd3eedb","repo":"t8y2/dbx","slug":"acl-principal-is-required","errorCode":null,"errorMessage":"ACL principal is required","messagePattern":"ACL principal is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agents/drivers/rocketmq/acl.go","lineNumber":115,"sourceCode":"\t}\n\tctx, cancel := context.WithTimeout(context.Background(), config.RequestTimeout)\n\tdefer cancel()\n\taddress, err := a.brokerAddressForName(stringValue(params, \"brokerName\"))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tentries, _ := params[\"acls\"].([]any)\n\tfor _, raw := range entries {\n\t\tentry, _ := raw.(map[string]any)\n\t\tif _, hasAccessKey := entry[\"accessKey\"]; hasAccessKey || entry[\"secretKey\"] != nil {\n\t\t\tif err := client.UpdatePlainAccessConfig(ctx, address, plainAccessConfig(entry)); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tsubject := strings.TrimPrefix(stringValue(entry, \"principal\", \"subject\"), \"User:\")\n\t\tif subject == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"ACL principal is required\")\n\t\t}\n\t\tresource := stringValue(entry, \"resourceName\")\n\t\tif resource == \"\" {\n\t\t\tresource = \"*\"\n\t\t}\n\t\thost := stringValue(entry, \"host\")\n\t\tif host == \"\" {\n\t\t\thost = \"*\"\n\t\t}\n\t\tdecision := stringValue(entry, \"permissionType\")\n\t\tif decision == \"\" {\n\t\t\tdecision = \"ALLOW\"\n\t\t}\n\t\tacl := aclWire{Subject: subject, Policies: []aclPolicyWire{{Entries: []aclEntryWire{{\n\t\t\tResource: resource, Actions: []string{mapACLOperation(stringValue(entry, \"operation\"))},\n\t\t\tSourceIPs: []string{host}, Decision: decision,\n\t\t}}}}}\n\t\tbody, marshalErr := json.Marshal(acl)","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/rocketmq/acl.go#L97-L133","documentation":"createACLs validates each ACL entry and requires a non-empty principal (or 'subject') after stripping the optional 'User:' prefix. The error is thrown before any admin API call when an entry in the acls/ACL config array lacks a principal, because RocketMQ ACL subjects must identify a user.","triggerScenarios":"Calling an ACL dispatch action whose entries array contains an object with no 'principal'/'subject' key, an empty string, or only the literal 'User:' prefix with nothing after it.","commonSituations":"Hand-written JSON/YAML ACL configs with a typo like 'pricipal' or 'user'; generating entries programmatically where the user field is empty; copying IAM-style configs that use 'subject' instead of 'principal'.","solutions":["Add a non-empty 'principal' (or 'subject') field to every ACL entry, e.g. \"principal\": \"User:appReader\"","Fix key-name typos so the entry actually uses 'principal' or 'subject'","Filter/validate entries in your config pipeline before dispatching createAcls"],"exampleFix":"// before\n{\"resourceName\": \"test-topic\", \"perms\": [\"PUB\"]}\n// after\n{\"principal\": \"User:appReader\", \"resourceName\": \"test-topic\", \"perms\": [\"PUB\"]}","handlingStrategy":"validation","validationCode":"for i, e := range entries {\n    if strings.TrimPrefix(stringValue(e, \"principal\", \"subject\"), \"User:\") == \"\" {\n        return fmt.Errorf(\"entry %d: principal is required\", i)\n    }\n}","typeGuard":"func hasPrincipal(entry map[string]any) bool {\n    return strings.TrimPrefix(stringValue(entry, \"principal\", \"subject\"), \"User:\") != \"\"\n}","tryCatchPattern":null,"preventionTips":["Always include a 'principal': 'User:<name>' in every ACL entry","Lint ACL config files for required keys before deployment","Generate ACL entries from a typed struct, not raw maps"],"tags":["acl","validation","configuration"],"backgroundTag":"missing-required-field","analyzedSha":"c0390bff16418b651f4728520d99adf8ce48829a","analyzedAt":"2026-09-05T23:05:10.900Z","contentChangedAt":"2026-09-05T23:05:10.900Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}