{"record":{"id":"ace5c8fce31304e1","repo":"supabase/supabase","slug":"method-method-not-allowed-ace5c8","errorCode":null,"errorMessage":"Method ${method} Not Allowed","messagePattern":"Method (.+?) Not Allowed","errorType":"http","errorClass":null,"httpStatus":405,"severity":"warning","filePath":"apps/studio/pages/api/ai/sql/filter-v1.ts","lineNumber":24,"sourceCode":"import { DEFAULT_COMPLETION_MODEL } from '@/lib/ai/model.utils'\nimport { apiWrapper } from '@/lib/api/apiWrapper'\nimport {\n  filterGroupSchemaForAI,\n  requestSchema,\n  serializeOperators,\n  serializeOptions,\n  validateFilterGroup,\n} from '@/lib/api/filterHelpers'\n\nasync function handler(req: NextApiRequest, res: NextApiResponse) {\n  const { method } = req\n\n  switch (method) {\n    case 'POST':\n      return handlePost(req, res)\n    default:\n      res.setHeader('Allow', ['POST'])\n      res.status(405).json({ data: null, error: { message: `Method ${method} Not Allowed` } })\n  }\n}\n\nexport async function handlePost(req: NextApiRequest, res: NextApiResponse) {\n  const parseResult = requestSchema.safeParse(req.body)\n\n  if (!parseResult.success) {\n    const errorMessage = parseResult.error.errors.map((e) => e.message).join(', ')\n    return res.status(400).json({ error: errorMessage })\n  }\n\n  const { prompt, filterProperties } = parseResult.data\n\n  try {\n    const { modelParams, error: modelError } = await getModel({\n      provider: 'openai',\n      modelEntry: DEFAULT_COMPLETION_MODEL,\n    })","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/supabase/supabase/blob/beee91b9c2228dd57302dec75c733baaa84ab543/apps/studio/pages/api/ai/sql/filter-v1.ts#L6-L42","documentation":"HTTP 405 from the filter-v1 route when the request method is not POST. Same switch/default pattern as the other AI routes: only 'POST' is handled, everything else gets Allow: POST and this interpolated message.","triggerScenarios":"GET request to /api/ai/sql/filter-v1, an OPTIONS preflight, or a client using PUT/PATCH. Also any method string that doesn't strictly equal 'POST' (whitespace, casing).","commonSituations":"Browser navigation to the URL, curl without -X POST, a fetch wrapper defaulting to GET, or a proxy rewriting the verb.","solutions":["Send method: 'POST' with a JSON body to /api/ai/sql/filter-v1.","Use curl -X POST for manual testing.","Confirm no trailing whitespace in the method string."],"exampleFix":"// before\nfetch('/api/ai/sql/filter-v1')\n// after\nfetch('/api/ai/sql/filter-v1', {\n  method: 'POST',\n  headers: { 'Content-Type': 'application/json' },\n  body: JSON.stringify({ prompt: 'show active users', filterProperties: [...] }),\n})","handlingStrategy":"validation","validationCode":"const opts = { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ prompt, filterProperties }) }\nif (opts.method !== 'POST') throw new Error('filter-v1 requires POST')","typeGuard":"function isPostInit(init?: RequestInit): init is RequestInit & { method: 'POST' } {\n  return !!init && (init.method ?? 'GET') === 'POST'\n}","tryCatchPattern":null,"preventionTips":["Centralize filter-v1 calls behind a typed client that hard-codes POST.","Block GET to /api/ai/sql/* at the proxy so browser hits never reach the handler."],"tags":["http","api-route","method-not-allowed","filter"],"backgroundTag":null,"analyzedSha":"beee91b9c2228dd57302dec75c733baaa84ab543","analyzedAt":"2026-08-12T06:51:48.935Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}