{"record":{"id":"e89d33e6ad9cc384","repo":"Budibase/budibase","slug":"file-must-contain-a-valid-openapi-schema","errorCode":null,"errorMessage":"File must contain a valid OpenAPI schema","messagePattern":"File must contain a valid OpenAPI schema","errorType":"http","errorClass":"HTTPError","httpStatus":400,"severity":"error","filePath":"packages/server/src/api/controllers/restTemplate.ts","lineNumber":90,"sourceCode":"      throw new HTTPError(\"Template name is required\", 400)\n    }\n    if (typeof description !== \"string\") {\n      throw new HTTPError(\"Template description is required\", 400)\n    }\n\n    const fileExtension = getFileExtension(uploadDetails.filename)\n    const data = await readFile(uploadDetails.filepath, \"utf8\")\n    let importer\n    let info\n    try {\n      importer = await createImporter({ data })\n      const source = importer.getSource().getImportSource()\n      if (source !== \"openapi2.0\" && source !== \"openapi3.0\") {\n        throw new Error(\"Unsupported OpenAPI source\")\n      }\n      info = importer.getInfo()\n    } catch {\n      throw new HTTPError(\"File must contain a valid OpenAPI schema\", 400)\n    }\n\n    ctx.body = {\n      template: await sdk.restTemplates.create({\n        name,\n        description,\n        data,\n        fileExtension,\n        operationsCount: info.endpoints.length,\n      }),\n    }\n  } finally {\n    await unlink(uploadDetails.filepath).catch(() => {})\n  }\n}\n\nexport const update = async (\n  ctx: UserCtx<","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/api/controllers/restTemplate.ts#L72-L108","documentation":"This 400 HTTPError wraps any failure while parsing the uploaded file as an OpenAPI 2.0 (Swagger) or 3.0 document. createImporter builds a format importer from the file contents; if parsing fails or the detected import source is anything other than openapi2.0/openapi3.0 (e.g. Postman, curl, GraphQL collections), the original error is discarded and this generic 400 is raised.","triggerScenarios":"Uploading a file whose contents are not valid JSON/YAML; uploading a valid file in an unsupported collection format (e.g. Postman v2.1 export); uploading a file with a .json/.yaml extension but malformed or non-OpenAPI schema content.","commonSituations":"Exporting specs from API tools that produce non-OpenAPI formats; hand-edited specs with YAML syntax errors; OpenAPI 3.1 documents rejected by the older parser; uploading a README or CSV renamed to .json.","solutions":["Validate the file locally against the OpenAPI 2.0 or 3.0 schema before uploading (e.g. with a swagger/openapi validator)","Fix JSON/YAML syntax errors in the spec; ensure required fields like openapi/swagger, info and paths are present","Convert unsupported formats (Postman, 3.1) to OpenAPI 3.0 before uploading","Confirm the file extension is .json, .yaml or .yml so the correct parser is selected"],"exampleFix":"// before\nopenapi: 3.1.0   # unsupported version\n// after\nopenapi: 3.0.3\ninfo:\n  title: My API\n  version: 1.0.0\npaths: {}","handlingStrategy":"validation","validationCode":"const spec = yamlOrJson.parse(fileContent)\nif (!spec || !(spec.openapi?.startsWith(\"3.0\") || spec.swagger === \"2.0\")) {\n  throw new Error(\"File is not an OpenAPI 2.0/3.0 document\")\n}","typeGuard":"const isOpenAPI = (v: unknown): v is { openapi?: string; swagger?: string; paths: Record<string, unknown> } =>\n  typeof v === \"object\" && v !== null &&\n  (\"openapi\" in v || \"swagger\" in v) && \"paths\" in v","tryCatchPattern":"try {\n  await uploadTemplate(form)\n} catch (e) {\n  if (e?.status === 400 && /valid OpenAPI schema/.test(e?.message)) {\n    // validate the spec locally and report parse errors to the user\n  } else throw e\n}","preventionTips":["Validate specs with a swagger/openapi validator before upload","Stick to OpenAPI 2.0 or 3.0.x (avoid 3.1 and tool exports like Postman)","Use .json/.yaml/.yml extensions matching the actual content format"],"tags":["validation","openapi","http-400","file-parsing"],"backgroundTag":"invalid-openapi-schema","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}