{"record":{"id":"4de47957f22b62ea","repo":"supabase/supabase","slug":"method-method-not-allowed-4de479","errorCode":null,"errorMessage":"Method ${method} Not Allowed","messagePattern":"Method (.+?) Not Allowed","errorType":"http","errorClass":null,"httpStatus":405,"severity":"warning","filePath":"apps/studio/pages/api/platform/storage/[ref]/buckets/[id]/objects/index.ts","lineNumber":16,"sourceCode":"import { NextApiRequest, NextApiResponse } from 'next'\n\nimport { apiWrapper } from '@/lib/api/apiWrapper'\nimport { selfHostedSupabaseAdmin as supabase } from '@/lib/api/self-hosted-admin'\n\nexport default (req: NextApiRequest, res: NextApiResponse) => apiWrapper(req, res, handler)\n\nasync function handler(req: NextApiRequest, res: NextApiResponse) {\n  const { method } = req\n\n  switch (method) {\n    case 'DELETE':\n      return handleDelete(req, res)\n    default:\n      res.setHeader('Allow', ['DELETE'])\n      res.status(405).json({ data: null, error: { message: `Method ${method} Not Allowed` } })\n  }\n}\n\nconst handleDelete = async (req: NextApiRequest, res: NextApiResponse) => {\n  const { id } = req.query\n  const { paths } = req.body\n\n  const { data, error } = await supabase.storage.from(id as string).remove(paths as string[])\n  if (error) {\n    return res.status(400).json({ error: { message: error.message } })\n  }\n\n  return res.status(200).json(data)\n}\n","sourceCodeStart":1,"sourceCodeEnd":31,"githubUrl":"https://github.com/supabase/supabase/blob/beee91b9c2228dd57302dec75c733baaa84ab543/apps/studio/pages/api/platform/storage/[ref]/buckets/[id]/objects/index.ts#L1-L31","documentation":"This route removes (deletes) storage objects via supabase.storage.from(id).remove(paths) and accepts only DELETE. The paths array comes from req.body. The default case returns 405 with \"Method ${method} Not Allowed\" and Allow: ['DELETE']. Using POST is incorrect.","triggerScenarios":"Sending POST to delete objects (some APIs use POST for bulk delete). Sending GET or PUT to `/api/platform/storage/{ref}/buckets/{id}/objects`. A client assuming bulk-delete uses POST.","commonSituations":"Developer expecting POST for a bulk-delete action (common in some REST APIs). Confusion between this object-deletion route and the bucket-level routes. A client library that uses a different method convention for bulk operations.","solutions":["Use DELETE with a JSON body containing { paths: ['path/to/file1', 'path/to/file2'] }.","Do not use POST — this route only accepts DELETE for object removal.","Check the Allow: ['DELETE'] response header."],"exampleFix":"// before — POST for bulk delete\nawait fetch(`/api/platform/storage/${ref}/buckets/${id}/objects`, {\n  method: 'POST',\n  body: JSON.stringify({ paths }),\n})\n\n// after — DELETE\nawait fetch(`/api/platform/storage/${ref}/buckets/${id}/objects`, {\n  method: 'DELETE',\n  body: JSON.stringify({ paths }),\n})","handlingStrategy":"validation","validationCode":"// Object deletion uses DELETE with body, not POST\nif (method !== 'DELETE') {\n  throw new Error('Object removal requires DELETE with { paths } in the body')\n}","typeGuard":"function isObjectRemoveMethod(method: string): method is 'DELETE' {\n  return method === 'DELETE'\n}","tryCatchPattern":null,"preventionTips":["Use DELETE (not POST) for bulk object removal — paths travel in the body.","Do not confuse this with the bucket-level DELETE route."],"tags":["http-405","method-not-allowed","nextjs-api-route","self-hosted","storage","objects"],"backgroundTag":null,"analyzedSha":"beee91b9c2228dd57302dec75c733baaa84ab543","analyzedAt":"2026-08-12T06:51:48.935Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}