supabase/supabase · warning
Method ${method} Not Allowed
Error message
Method ${method} Not Allowed What it means
HTTP 405 from the MFA-factors admin route. Only DELETE is handled (it lists and removes all MFA factors for a user via selfHostedSupabaseAdmin.auth.admin.mfa); all other methods return `{ data: null, error: { message: 'Method ${method} Not Allowed' } }` with Allow: DELETE. A 405 here means the wrong verb reached an admin-only destructive endpoint.
Source
Thrown at apps/studio/pages/api/platform/auth/[ref]/users/[id]/factors.ts:16
import { NextApiRequest, NextApiResponse } from 'next'
import { apiWrapper } from '@/lib/api/apiWrapper'
import { selfHostedSupabaseAdmin as supabase } from '@/lib/api/self-hosted-admin'
export default (req: NextApiRequest, res: NextApiResponse) => apiWrapper(req, res, handler)
async function handler(req: NextApiRequest, res: NextApiResponse) {
const { method } = req
switch (method) {
case 'DELETE':
return handleDelete(req, res)
default:
res.setHeader('Allow', ['DELETE'])
res.status(405).json({ data: null, error: { message: `Method ${method} Not Allowed` } })
}
}
const handleDelete = async (req: NextApiRequest, res: NextApiResponse) => {
const { id } = req.query
// Get all factors for the user
const { data: factors, error } = await supabase.auth.admin.mfa.listFactors({
userId: id as string,
})
if (error) {
return res.status(400).json({ error: { message: error.message } })
}
factors?.factors.forEach(async (factor: any) => {
const { error } = await supabase.auth.admin.mfa.deleteFactor({
id: factor.id,
userId: id as string,View on GitHub (pinned to beee91b9c2)
Solutions
- Send DELETE: `fetch(`/api/platform/auth/${ref}/users/${id}/factors`, { method: 'DELETE' })`.
- If you needed to list factors, hit the pg/supabase admin list endpoint directly, not this route.
- Verify the calling code is not falling back to a default GET helper.
- Only add a non-DELETE case if the route is intended to support listing/creating.
Example fix
// before
await fetch(`/api/platform/auth/${ref}/users/${id}/factors`)
// after
await fetch(`/api/platform/auth/${ref}/users/${id}/factors`, { method: 'DELETE' }) Defensive patterns
Strategy: validation
Validate before calling
if (method.toUpperCase() !== 'DELETE') {
throw new Error('factors route only supports DELETE')
} Type guard
type FactorMethod = 'DELETE'
function isFactorMethod(m: string): m is FactorMethod {
return m.toUpperCase() === 'DELETE'
} Try / catch
const res = await fetch(url, { method: 'DELETE' })
if (res.status === 405) {
throw new Error('Use DELETE to remove MFA factors; this route does not list/create')
} Prevention
- Remember this route only deletes — list factors elsewhere.
- Set method explicitly on destructive calls.
- Drive the call through a typed mutation in data/fetchers.ts.
When it happens
Trigger: Calling /api/platform/auth/[ref]/users/[id]/factors with GET (expecting to list factors), POST (creating), or PUT/PATCH; or a fetch missing `method: 'DELETE'`.
Common situations: Assuming the endpoint lists factors (it does not — it only deletes); a UI 'Remove MFA factors' button that drops the method and sends GET; integration tests reusing a GET helper.
Related errors
- Method ${method} Not Allowed
- Method ${method} Not Allowed
- Method ${method} Not Allowed
- Method ${method} Not Allowed
- Method ${method} Not Allowed
AI-assisted analysis of supabase/supabase@beee91b9c2 (2026-08-12).
Data as JSON: /api/errors/728b16d6347fcd2a.
Report an issue: GitHub.