{"record":{"id":"2870f8789c43bbb0","repo":"hcengineering/platform","slug":"missing-required-fields-type-plan","errorCode":null,"errorMessage":"Missing required fields: type, plan","messagePattern":"Missing required fields: type, plan","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"services/payment/pod-payment/src/server.ts","lineNumber":227,"sourceCode":"          const loginInfo = req.loginInfo as WorkspaceLoginInfo\n\n          if (accountUuid === undefined) {\n            res.status(401).json({ error: 'Missing account in token' })\n            return\n          }\n\n          if (workspaceUuid === undefined) {\n            res.status(401).json({ error: 'Missing workspace in token' })\n            return\n          }\n\n          if (loginInfo?.workspaceUrl === undefined) {\n            res.status(401).json({ error: 'Missing workspace url in login info' })\n            return\n          }\n\n          if (request.type === undefined || request.plan === undefined) {\n            res.status(400).json({ error: 'Missing required fields: type, plan' })\n            return\n          }\n\n          let createSubResponse: CheckoutResponse\n\n          try {\n            createSubResponse = await provider.createSubscription(\n              ctx,\n              request,\n              workspaceUuid,\n              loginInfo.workspaceUrl,\n              accountUuid\n            )\n          } catch (err) {\n            ctx.error('Failed to create subscription at provider', { err })\n            res.status(500).json({ error: 'Failed to create subscription at provider' })\n            return\n          }","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/services/payment/pod-payment/src/server.ts#L209-L245","documentation":"The subscribe endpoint validates that the request body (a SubscribeRequest) contains both 'type' ('tier' or 'support') and 'plan' before calling the payment provider. If either is undefined it returns HTTP 400 without contacting the provider. This is a plain request-shape validation failure, so the provider is never invoked.","triggerScenarios":"POST /api/v1/subscriptions/:workspace/subscribe with a JSON body missing 'type' and/or 'plan', sending them under wrong names (e.g. 'planId', 'subscriptionType'), sending an empty body, or a client that fails to JSON-serialize the body so req.body only carries partial fields.","commonSituations":"Typos or renamed fields after an API client upgrade; curl/Postman calls with forgotten body; frontend form submitted before plan selection; Content-Type not application/json so body fields end up undefined.","solutions":["Include both required fields in the request body: { \"type\": \"tier\"|\"support\", \"plan\": \"<plan-name>\" }.","Verify the request Content-Type is application/json so Express parses the body (and that a body parser middleware is enabled).","Check client code for renamed fields after a client-library upgrade and align with SubscribeRequest.","Add client-side form validation ensuring a plan is chosen before submitting."],"exampleFix":"// before\nawait fetch(url, { method: 'POST', body: JSON.stringify({ plan: 'epic' }) })\n\n// after\nawait fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ type: 'tier', plan: 'epic' }) })","handlingStrategy":"validation","validationCode":"function isValidSubscribeRequest(body: unknown): body is SubscribeRequest {\n  const b = body as SubscribeRequest\n  return (b.type === 'tier' || b.type === 'support') && typeof b.plan === 'string' && b.plan.length > 0\n}\n// call before POST: if (!isValidSubscribeRequest(payload)) return","typeGuard":"function isSubscribeRequest(v: unknown): v is SubscribeRequest {\n  const b = v as Partial<SubscribeRequest>\n  return (b.type === 'tier' || b.type === 'support') && typeof b.plan === 'string'\n}","tryCatchPattern":"const res = await fetch(subscribeUrl, opts)\nif (res.status === 400) {\n  const body = await res.json()\n  if (body.error === 'Missing required fields: type, plan') {\n    // fix payload shape and resubmit; this is not retryable as-is\n  }\n}","preventionTips":["Share the SubscribeRequest type between client and server (generated from a shared package).","Validate the payload with a schema (zod/valibot) before sending.","Always send Content-Type: application/json and confirm body-parser middleware is enabled.","Keep API client versions in sync with server route contract changes."],"tags":["http-400","validation","payment","request-body"],"backgroundTag":"missing-required-request-fields","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}