{"record":{"id":"cd944ec499fa3dd3","repo":"Tencent/WeKnora","slug":"w-v-cd944e","errorCode":null,"errorMessage":"%w: %v","messagePattern":"%w: %v","errorType":"validation","errorClass":"errInvalidExternalUserID","httpStatus":401,"severity":"error","filePath":"internal/middleware/auth.go","lineNumber":587,"sourceCode":"\t}\n\tif tenant == nil || tenantID == 0 {\n\t\treturn fallback, nil\n\t}\n\tcfg := tenant.APIPrincipalConfig\n\tif cfg == nil || cfg.Mode == \"\" || cfg.Mode == types.APIPrincipalModeTenant {\n\t\treturn fallback, nil\n\t}\n\tswitch cfg.Mode {\n\tcase types.APIPrincipalModeDirect:\n\t\texternalUserID := strings.TrimSpace(header.Get(defaultExternalUserIDHeader))\n\t\tif externalUserID == \"\" {\n\t\t\tif cfg.RequireDirectHeader {\n\t\t\t\treturn types.Principal{}, errMissingDirectHeader\n\t\t\t}\n\t\t\treturn fallback, nil\n\t\t}\n\t\tif err := validateExternalUserID(externalUserID); err != nil {\n\t\t\treturn types.Principal{}, fmt.Errorf(\"%w: %v\", errInvalidExternalUserID, err)\n\t\t}\n\t\treturn types.Principal{\n\t\t\tType: types.PrincipalAPIExternalUser,\n\t\t\tID:   strconv.FormatUint(tenantID, 10) + \":\" + externalUserID,\n\t\t}, nil\n\tcase types.APIPrincipalModeSignedToken:\n\t\texternalUserID, err := verifyExternalUserJWT(header.Get(defaultExternalUserTokenHeader), tenantID, cfg.HMACSecret)\n\t\tif err != nil || externalUserID == \"\" {\n\t\t\tlogger.Warnf(ctx, \"invalid external user token for tenant=%d: %v\", tenantID, err)\n\t\t\treturn types.Principal{}, fmt.Errorf(\"%w: %w\", errInvalidExternalUserToken, err)\n\t\t}\n\t\tif err := validateExternalUserID(externalUserID); err != nil {\n\t\t\treturn types.Principal{}, fmt.Errorf(\"%w: %v\", errInvalidExternalUserID, err)\n\t\t}\n\t\treturn types.Principal{\n\t\t\tType: types.PrincipalAPIExternalUser,\n\t\t\tID:   strconv.FormatUint(tenantID, 10) + \":\" + externalUserID,\n\t\t}, nil","sourceCodeStart":569,"sourceCodeEnd":605,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/middleware/auth.go#L569-L605","documentation":"In internal/middleware/auth.go:587, resolveAPIPrincipal (APIPrincipalModeDirect) wraps errInvalidExternalUserID with the underlying validation failure from validateExternalUserID. The external user id supplied in the direct header is empty, too long, or contains control characters, so no Principal is resolved and the request is rejected.","triggerScenarios":"Tenant configured with APIPrincipalModeDirect; request carries the external user id header (defaultExternalUserIDHeader) with a value that is empty after trim, longer than maxExternalUserIDLen, or contains bytes <0x20 or 0x7f.","commonSituations":"Client sends a padded/newline-terminated user id from a misconfigured header; integration passes an oversized UUID-with-prefix string; id built by concatenating fields picks up a tab or control character.","solutions":["Send a non-empty external user id in the direct header with no control characters and within maxExternalUserIDLen.","Trim whitespace/newlines from the value on the client side before setting the header.","Check errors.Is(err, errInvalidExternalUserID) and surface the inner message to fix the exact violation (empty / too long / invalid characters)."],"exampleFix":"// before (client)\nreq.Header.Set(\"X-External-User-ID\", userID + \"\\n\") // control char -> rejected\n// after\nreq.Header.Set(\"X-External-User-ID\", strings.TrimSpace(userID))","handlingStrategy":"try-catch","validationCode":"id := strings.TrimSpace(extUserID)\nif id == \"\" || len(id) > maxExternalUserIDLen || strings.ContainsFunc(id, func(r rune) bool { return r < 0x20 || r == 0x7f }) {\n    // fix the header value before sending the request\n}","typeGuard":"func validExternalUserID(id string) bool {\n    id = strings.TrimSpace(id)\n    if id == \"\" || len(id) > maxExternalUserIDLen { return false }\n    for _, r := range id { if r < 0x20 || r == 0x7f { return false } }\n    return true\n}","tryCatchPattern":"if err != nil {\n    if errors.Is(err, errInvalidExternalUserID) {\n        // correct the external user id header and retry once\n    }\n}","preventionTips":["Trim and length-check external user ids at the client boundary.","Reject ids containing control characters in your own validation layer.","Map long provider identifiers to short stable IDs."],"tags":["authentication","api-key","validation"],"backgroundTag":"invalid-external-user-id","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}