juspay/hyperswitch · error · Error
Payment method create failed with status ${response.status}:
Error message
Payment method create failed with status ${response.status}: ${JSON.stringify(response.body)} What it means
Thrown by the paymentMethodCreateCall (v2, port 8082) custom Cypress command: on success it asserts that payment_method_type, payment_method_subtype, and storage_type echo back from the response; any status outside the success branch hits the else-throw, which embeds both the status and JSON.stringify(response.body). Because the full body is included, the message is self-describing — it usually contains the server's validation error verbatim.
Source
Thrown at cypress-tests/cypress/support/commands.js:8375
failOnStatusCode: false,
}).then((response) => {
if (response.status === 200) {
globalState.set("paymentMethodId", response.body.id);
expect(requestBody.customer_id, "customer_id").to.equal(
response.body.customer_id
);
expect(requestBody.payment_method_type, "payment_method_type").to.equal(
response.body.payment_method_type
);
expect(
requestBody.payment_method_subtype,
"payment_method_subtype"
).to.equal(response.body.payment_method_subtype);
expect(requestBody.storage_type, "storage_type").to.equal(
response.body.storage_type
);
} else {
throw new Error(
`Payment method create failed with status ${response.status}: ${JSON.stringify(response.body)}`
);
}
});
});
Cypress.Commands.add("getRawPaymentMethodDetailsCall", (globalState) => {
const apiKey = globalState.get("apiKey");
const profileId = globalState.get("profileId");
const paymentMethodId = globalState.get("paymentMethodId");
cy.request({
method: "GET",
url: `${globalState.get("pmServiceUrl")}/v1/payment-methods/${paymentMethodId}?fetch_raw_detail=true`,
headers: {
"Content-Type": "application/json",
Accept: "application/json",
"X-Profile-Id": profileId,View on GitHub (pinned to 9b8b89dc37)
Solutions
- Read the JSON body in the thrown message first — it contains the server's exact validation message; fix the named pmData field.
- Assert prerequisites before the call: globalState has apiKey, profileId, and customerId set (i.e. the customer-create step actually ran and succeeded).
- 401 -> refresh the API key; 404 -> confirm the v2 base URL/port (8082) and that the customer still exists in that environment.
- If a renamed payment_method_type/subtype/storage_type value: update the fixture to the current v2 enum values.
- 429/5xx -> retry after the service is healthy.
Example fix
// before: runs even when the customer step failed, producing an opaque 404
cy.paymentMethodCreateCall(globalState, pmData);
// after: fail fast with a clear cause when state is missing
const customerId = globalState.get('customerId');
if (!customerId) {
throw new Error('paymentMethodCreateCall: customerId missing in globalState — run customerCreateCall first');
}
cy.paymentMethodCreateCall(globalState, pmData); Defensive patterns
Strategy: validation
Validate before calling
// Run before paymentMethodCreateCall
function validatePaymentMethodCreateCall(globalState, pmData) {
for (const key of ['apiKey', 'profileId', 'customerId']) {
if (!globalState.get(key)) throw new Error(`paymentMethodCreateCall: ${key} missing in globalState — earlier step failed or skipped`);
}
for (const field of ['payment_method_type', 'payment_method_subtype', 'storage_type']) {
if (!pmData?.[field]) throw new Error(`paymentMethodCreateCall: pmData.${field} is required`);
}
} Type guard
// Narrow the response before asserting the echo fields, so a 4xx body never reaches .to.equal()
function isPaymentMethodCreated(body) {
return (
typeof body === 'object' &&
body !== null &&
typeof body.payment_method_type === 'string' &&
typeof body.payment_method_subtype === 'string' &&
typeof body.storage_type === 'string'
);
} Try / catch
// The thrown message already carries status + full JSON body; extract them for routing:
// try { ... } catch (e) {
// const m = e.message.match(/status (\d+): (.*)$/s);
// if (!m) throw e;
// const [, statusStr, bodyJson] = m;
// const status = Number(statusStr);
// const body = JSON.parse(bodyJson);
// if (status === 400) throw new Error(`fix pmData: ${body.error?.message}`);
// if (status === 401) throw new Error('refresh apiKey');
// if (status === 404) throw new Error('wrong v2 base URL/port or customer missing');
// throw e;
// } Prevention
- Chain test steps explicitly: customerCreateCall must succeed before paymentMethodCreateCall; assert customerId exists in globalState first.
- Fail fast with a clear precondition error instead of letting a missing customerId produce an opaque 404.
- Use the v2 credentials and base URL (port 8082) for v2 commands — never mix with v1 (8081).
- After server upgrades, re-verify the enum values for payment_method_type/subtype/storage_type in fixtures.
- Keep response bodies in thrown messages (JSON.stringify) — they are the fastest diagnostic you have.
When it happens
Trigger: 400 when pmData is missing/invalid payment_method_type, payment_method_subtype, or storage_type; 401 with a bad apiKey; 404 when the endpoint path is wrong or the referenced customer/profile does not exist; 422/400 when the customerId in globalState was never set (earlier customerCreateCall failed or was skipped, leaving paymentMethodId/customerId undefined); 5xx from the v2 service.
Common situations: Test-ordering dependency: this command runs before customerCreateCall populated globalState, so the request targets a missing customer; using v1 credentials/base URL (8081) against the v2 service (8082); connector schema change renaming subtypes; expired API key in the environment; data cleanup between runs deleting the customer the test assumed existed.
Related errors
- Please provide a baseUrl
- Unsupported baseUrl
- Unsupported keyIdType: ${keyIdType}
- Invalid config: missing path
- methodFlow input is required
AI-assisted analysis of juspay/hyperswitch@9b8b89dc37 (2026-08-16).
Data as JSON: /api/errors/47f74b7cc272fee6.
Report an issue: GitHub.