{"record":{"id":"183d638ee8124063","repo":"mastra-ai/mastra","slug":"not-found-183d63","errorCode":null,"errorMessage":"Not found","messagePattern":"Not found","errorType":"http","errorClass":"HTTPException","httpStatus":404,"severity":"error","filePath":"packages/server/src/server/handlers/channels.ts","lineNumber":96,"sourceCode":"    // Code-defined agents have no owner/ACL — route's requiresAuth /\n    // requiresPermission is the gate. Pass-through.\n    return;\n  }\n\n  if (action === 'connect') {\n    throw new HTTPException(404, { message: `Agent \"${agentId}\" not found` });\n  }\n\n  // Disconnect against an unknown agentId = orphan cleanup (stored agent was\n  // deleted but the channel installation row is still around). Allow it, but\n  // gate on channels:write so this isn't an \"any authenticated user\" backdoor.\n  // Follow the same no-auth-configured pass-through as assertWriteAccess.\n  const callerAuthorId = getCallerAuthorId(requestContext);\n  if (!callerAuthorId && !requestContext.get(MASTRA_USER_KEY)) return;\n  if (hasAdminBypass(requestContext, 'channels')) return;\n  if (hasScopedPermission({ requestContext, resource: 'channels', action: 'write' })) return;\n\n  throw new HTTPException(404, { message: 'Not found' });\n}\n\n// ============================================================================\n// Route Definitions\n// ============================================================================\n\n/**\n * GET /channels/platforms - List available channel platforms\n */\nexport const LIST_CHANNEL_PLATFORMS_ROUTE = createRoute({\n  method: 'GET',\n  path: '/channels/platforms',\n  responseType: 'json',\n  responseSchema: listChannelPlatformsResponseSchema,\n  summary: 'List channel platforms',\n  description: 'Returns available channel platforms and their configuration status',\n  tags: ['Channels'],\n  requiresAuth: true,","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/server/src/server/handlers/channels.ts#L78-L114","documentation":"The channels routes return HTTP 404 'Not found' when the request context has no authenticated identity (no caller author ID and no Mastra user), no admin bypass for 'channels', and no scoped 'channels:write' permission. It deliberately mirrors the no-auth-configured pass-through of assertWriteAccess: if the deployment has no auth configured at all, the check is skipped. This is an authorization failure disguised as a 404 to avoid leaking channel/agent existence to unauthorized callers.","triggerScenarios":"Calling the CONNECT or DISCONNECT channel route (POST connect/disconnect for a platform+agentId) while: (1) the request context lacks a caller author ID AND a MASTRA_USER_KEY user, in an auth-configured deployment; (2) the caller has no scoped permission {resource:'channels', action:'write'}; (3) admin bypass 'channels' is not enabled.","commonSituations":"Calling the server API with a missing or expired auth token so no identity is resolved; an API key or user scoped only to read permissions being used to connect/disconnect channels; RBAC roles that grant agents:write but not channels:write; tests or scripts hitting the route without forwarding the request context.","solutions":["Grant the calling user/agent a scoped permission with resource 'channels' and action 'write' (or 'connect'/'disconnect' equivalents your role config uses)","Ensure the request carries valid authentication so getCallerAuthorId or MASTRA_USER_KEY resolves an identity","Use an identity with admin bypass for the 'channels' resource if admin access is intended","If the deployment intentionally has no auth, verify auth is not partially configured, which disables the pass-through"],"exampleFix":"// before\nawait fetch('/api/channels/slack/connect', { method: 'POST', body }) // no auth header\n// after\nawait fetch('/api/channels/slack/connect', { method: 'POST', body, headers: { Authorization: `Bearer ${token}` } }) // token has channels:write","handlingStrategy":"validation","validationCode":"const hasChannelsWrite = permissions.some(p => p.resource === 'channels' && ['write','connect','disconnect'].includes(p.action));\nif (!hasChannelsWrite) throw new Error('Caller lacks channels:write permission');","typeGuard":"function canWriteChannels(perms: Array<{resource: string; action: string}> | undefined): boolean {\n  return Array.isArray(perms) && perms.some(p => p.resource === 'channels' && p.action === 'write');\n}","tryCatchPattern":"try {\n  await client.connectChannel({ platform, agentId });\n} catch (e) {\n  if (e.status === 404) {\n    // authorization hidden as 404: check identity + channels:write permission\n    console.error('Not authorized for channel operations or channel absent:', e.message);\n  }\n  throw e;\n}","preventionTips":["Always attach a valid auth token so an identity resolves in request context","Provision channels:write scope for service identities that manage channels","Keep admin bypass resources documented and audited","Remember 404 here may mean 'not allowed', not 'does not exist'"],"tags":["authorization","http-404","rbac","server-api"],"backgroundTag":"authorization-denied-as-not-found","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}