{"record":{"id":"d7693534608b0a38","repo":"juspay/hyperswitch","slug":"customer-create-call-failed-with-status-respons","errorCode":null,"errorMessage":"Customer create call failed with status: ${response.status} and message: ${response.body?.error?.message}","messagePattern":"Customer create call failed with status: (.+?) and message: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"cypress-tests/cypress/support/commands.js","lineNumber":8328,"sourceCode":"        expect(customerCreateBody.metadata, \"metadata\").to.deep.equal(\n          response.body.metadata\n        );\n        expect(customerCreateBody.address, \"address\").to.deep.equal(\n          response.body.address\n        );\n        expect(\n          customerCreateBody.phone_country_code,\n          \"phone_country_code\"\n        ).to.equal(response.body.phone_country_code);\n      } else if (response.status === 400) {\n        if (response.body.error.message.includes(\"already exists\")) {\n          expect(response.body.error.code).to.equal(\"IR_12\");\n          expect(response.body.error.message).to.equal(\n            \"Customer with the given `customer_id` already exists\"\n          );\n        }\n      } else {\n        throw new Error(\n          `Customer create call failed with status: ${response.status} and message: ${response.body?.error?.message}`\n        );\n      }\n    });\n  }\n);\n\n// Payment Methods Commands (v2 code - port 8082)\nCypress.Commands.add(\"paymentMethodCreateCall\", (globalState, pmData) => {\n  const apiKey = globalState.get(\"apiKey\");\n  const profileId = globalState.get(\"profileId\");\n  const customerId = globalState.get(\"customerId\");\n\n  const requestBody = {\n    ...pmData,\n    customer_id: customerId,\n  };\n","sourceCodeStart":8310,"sourceCodeEnd":8346,"githubUrl":"https://github.com/juspay/hyperswitch/blob/9b8b89dc378b62c9a6feda647bad4719d2de7699/cypress-tests/cypress/support/commands.js#L8310-L8346","documentation":"Thrown by the customerCreateCall custom Cypress command after POSTing a customer-create request with failOnStatusCode-style handling: status 200 goes through field-echo assertions (e.g. phone_country_code), status 400 is tolerated only when the message contains 'already exists' (asserting code IR_12 and the exact message), and every other status falls into the else-branch throw with status and error.message. It means the Customer API responded with a status the command does not consider a known-good outcome.","triggerScenarios":"401 with a bad/expired API key (globalState 'apiKey'); 403 when the key cannot access the profile (globalState 'profileId'); 404 from a wrong base URL or endpoint path; 400 with any message other than 'Customer with the given `customer_id` already exists' (e.g. invalid phone_country_code, invalid email format); 429 rate limiting; 5xx server errors.","commonSituations":"Reusing a hardcoded customer_id across runs and hitting a 400 whose message differs slightly from the asserted string; API key expired or belonging to another environment; base URL/port pointing at the wrong service version; profile not provisioned; server contract change altering the already-exists message so the 400 branch no longer matches and 400 now falls through to the throw.","solutions":["Parse the status and message out of the thrown text: 401 -> refresh/regenerate the API key in globalState; 403 -> check the key's access to the profile; 404 -> verify base URL and customers endpoint path.","If 400: diff the actual message against 'Customer with the given `customer_id` already exists' — if it is a different validation error, fix the offending field (phone_country_code, email, customer_id format) in the customer fixture.","Generate a unique customer_id per run (e.g. suffix with Date.now()/UUID) so the already-exists path only occurs when you intentionally test it.","If the message text changed in a new server version, update the command's expected string/code (IR_12) to match the current contract.","If 429/5xx: add retry with backoff or wait for service health before rerunning."],"exampleFix":"// before: fixed customer_id, collisions fall into the throw on message drift\ncy.customerCreateCall(globalState, { ...pmData, customer_id: 'cust_test_1' });\n\n// after: unique id per run; 400 branch only reached deliberately\nconst customerId = `cust_${Cypress.moment().format('x')}_${Cypress.spec.name}`;\ncy.customerCreateCall(globalState, { ...pmData, customer_id: customerId });","handlingStrategy":"validation","validationCode":"// Run before customerCreateCall\nfunction validateCustomerCreateCall(globalState, customerData) {\n  if (!globalState.get('apiKey')) throw new Error('customerCreateCall: apiKey missing in globalState');\n  if (!globalState.get('profileId')) throw new Error('customerCreateCall: profileId missing in globalState');\n  if (!customerData?.customer_id) throw new Error('customerCreateCall: customer_id required');\n  if (!/^[A-Za-z0-9_-]+$/.test(customerData.customer_id)) {\n    throw new Error(`customerCreateCall: invalid customer_id '${customerData.customer_id}'`);\n  }\n}","typeGuard":"// Distinguish the tolerated 409-style 'already exists' body from other failures\nfunction isAlreadyExistsError(body) {\n  return (\n    typeof body === 'object' &&\n    body !== null &&\n    body.error?.code === 'IR_12' &&\n    typeof body.error?.message === 'string' &&\n    body.error.message.includes('already exists')\n  );\n}","tryCatchPattern":"// Prefer result-object returns over throws so callers branch instead of catching:\n//   const r = await customerCreate(state, data);\n//   if (r.status === 400 && isAlreadyExistsError(r.body)) { /* reuse or regenerate id */ }\n// For the existing throwing command, callers in plain Node wrappers can do:\n// try { ... } catch (e) {\n//   const m = e.message.match(/status: (\\d+) and message: (.*)$/);\n//   if (!m) throw e;\n//   const [, status, msg] = m;\n//   if (status === '400' && !msg.includes('already exists')) throw new Error(`payload invalid: ${msg}`);\n//   if (status === '401') throw new Error('refresh API key');\n// }","preventionTips":["Generate a unique customer_id per run (timestamp/UUID suffix) so the 400 branch is only hit intentionally.","Set apiKey/profileId in globalState once in a before() hook and assert they exist before any create call.","Pin the base URL per environment and never mix keys from one env with URLs from another.","When upgrading the server, re-check the exact 'already exists' message and IR_12 code the command asserts.","Log x-request-id from responses so failures can be traced in server logs."],"tags":["api","customers","cypress","http","test-data"],"backgroundTag":null,"analyzedSha":"9b8b89dc378b62c9a6feda647bad4719d2de7699","analyzedAt":"2026-08-16T09:01:53.433Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}