{"record":{"id":"052406d7a54a33ff","repo":"RocketChat/Rocket.Chat","slug":"invalid-oauth-client","errorCode":null,"errorMessage":"Invalid OAuth client","messagePattern":"Invalid OAuth client","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"apps/meteor/client/views/oauth/hooks/useOAuthAppQuery.ts","lineNumber":19,"sourceCode":"import type { IOAuthApps } from '@rocket.chat/core-typings';\nimport { useEndpoint } from '@rocket.chat/ui-contexts';\nimport type { UseQueryOptions } from '@tanstack/react-query';\nimport { useQuery } from '@tanstack/react-query';\n\ntype UseOAuthAppQueryOptions = Omit<\n\tUseQueryOptions<IOAuthApps, unknown, IOAuthApps, readonly ['oauth-app', { readonly clientId: string | undefined }]>,\n\t'queryKey' | 'queryFn'\n>;\n\nexport const useOAuthAppQuery = (clientId: string | undefined, options?: UseOAuthAppQueryOptions) => {\n\tconst getOAuthApp = useEndpoint('GET', '/v1/oauth-apps.get');\n\n\treturn useQuery({\n\t\tqueryKey: ['oauth-app', { clientId }] as const,\n\n\t\tqueryFn: async () => {\n\t\t\tif (!clientId) {\n\t\t\t\tthrow new Error('Invalid OAuth client');\n\t\t\t}\n\n\t\t\tconst { oauthApp } = await getOAuthApp({ clientId });\n\t\t\treturn {\n\t\t\t\t...oauthApp,\n\t\t\t\t_createdAt: new Date(oauthApp._createdAt),\n\t\t\t\t_updatedAt: new Date(oauthApp._updatedAt),\n\t\t\t};\n\t\t},\n\t\t...options,\n\t});\n};\n","sourceCodeStart":1,"sourceCodeEnd":32,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/client/views/oauth/hooks/useOAuthAppQuery.ts#L1-L32","documentation":"useOAuthAppQuery's queryFn throws 'Invalid OAuth client' as a first guard when clientId is undefined — the hook cannot call GET /v1/oauth-apps.get without it. Because react-query executes queryFn as soon as the query mounts (unless disabled), an absent clientId turns into a failed query rather than a skipped one.","triggerScenarios":"Rendering the OAuth app admin/route that uses this hook without a clientId route param (bad link, missing parameter), or passing undefined during a parent's loading state while the query is still enabled.","commonSituations":"Deep links or bookmarks to /oauth/... missing the client id segment; refactors renaming the route param; component reused in contexts where the id arrives asynchronously.","solutions":["Pass enabled: Boolean(clientId) through options so the query waits for the id.","Fix the source of clientId (route param name, link generation) so it is present.","Render a loading/empty state while clientId is undefined."],"exampleFix":"// before\nconst { data } = useOAuthAppQuery(clientId);\n\n// after\nconst { data } = useOAuthAppQuery(clientId, {\n  enabled: Boolean(clientId),\n});","handlingStrategy":"validation","validationCode":"useOAuthAppQuery(clientId, {\n  enabled: Boolean(clientId), // queryFn never runs with undefined\n});","typeGuard":"const hasClientId = (v: string | undefined): v is string => Boolean(v && v.length > 0);","tryCatchPattern":null,"preventionTips":["Always pass enabled: Boolean(clientId) for id-dependent queries.","Validate route params before rendering id-driven components.","Show a loading skeleton while the param resolves."],"tags":["oauth","react-query","routing"],"backgroundTag":"missing-route-param","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","contentChangedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}