{"record":{"id":"bd76a60e653f2908","repo":"Significant-Gravitas/AutoGPT","slug":"search-query-must-be-at-least-3-characters","errorCode":null,"errorMessage":"Search query must be at least 3 characters.","messagePattern":"Search query must be at least 3 characters\\.","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"autogpt_platform/backend/backend/api/features/admin/rate_limit_admin_routes.py","lineNumber":265,"sourceCode":"\n\n@router.get(\n    \"/rate_limit/search_users\",\n    response_model=list[UserSearchResult],\n    summary=\"Search Users by Name or Email\",\n)\nasync def admin_search_users(\n    query: str,\n    limit: int = 20,\n    admin_user_id: str = Security(get_user_id),\n) -> list[UserSearchResult]:\n    \"\"\"Search users by partial email or name. Admin-only.\n\n    Queries the User table directly — returns results even for users\n    without credit transaction history.\n    \"\"\"\n    if len(query.strip()) < 3:\n        raise HTTPException(\n            status_code=400,\n            detail=\"Search query must be at least 3 characters.\",\n        )\n    logger.info(\"Admin %s searching users with query=%r\", admin_user_id, query)\n    results = await search_users(query, limit=max(1, min(limit, 50)))\n    return [UserSearchResult(user_id=uid, user_email=email) for uid, email in results]\n","sourceCodeStart":247,"sourceCodeEnd":272,"githubUrl":"https://github.com/Significant-Gravitas/AutoGPT/blob/9c8bb5550f446ba5d3046b78896578742495b3cf/autogpt_platform/backend/backend/api/features/admin/rate_limit_admin_routes.py#L247-L272","documentation":"A 400 validation error from the admin user-search endpoint: the query parameter, after strip(), is shorter than 3 characters. The endpoint searches users by partial email/name and enforces a minimum length to prevent near-empty queries from scanning or returning the whole user table.","triggerScenarios":"GET /rate_limit/search_users?query=ab (1-2 non-space chars), or a query made only of whitespace such as query=%20%20 (strips to empty), or a client sending the raw first keystrokes of a typeahead box before debouncing.","commonSituations":"Frontend typeahead firing on every keypress without debounce, sending 1-2 character prefixes; passing an undefined/null query that serializes to an empty or short string; over-aggressive trimming client-side leaving an empty string.","solutions":["Client-side: debounce the typeahead (e.g. 300ms) and only fire the request once the trimmed query length is >= 3.","Client-side: strip whitespace before checking length so '  a ' does not slip through as a 1-char effective query.","If short queries must work, lengthen the query (full email prefix) rather than changing the endpoint; the 3-char floor is an intentional scan guard."],"exampleFix":"// before\nfetch(`/rate_limit/search_users?query=${input}`)  // fires on every keystroke\n\n// after\nconst q = input.trim();\nif (q.length >= 3) fetch(`/rate_limit/search_users?query=${encodeURIComponent(q)}`)","handlingStrategy":"validation","validationCode":"const q = query.trim();\nif (q.length < 3) return []; // don't call the endpoint\nreturn await searchUsers(q);","typeGuard":"function isSearchableQuery(q: string): boolean {\n  return q.trim().length >= 3;\n}","tryCatchPattern":null,"preventionTips":["Debounce typeahead ~300ms and gate on trimmed length >= 3.","Trim before length checks so whitespace-only input never reaches the API."],"tags":["backend","admin","search","validation","http-400"],"backgroundTag":null,"analyzedSha":"9c8bb5550f446ba5d3046b78896578742495b3cf","analyzedAt":"2026-08-14T17:17:21.957Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}