juspay/hyperswitch · error · Error
Health Check failed with status: `${response.status}` and bo
Error message
Health Check failed with status: `${response.status}` and body: `${response.body}` What it means
Thrown by the healthCheck Cypress command in cypress-tests/cypress/support/commands.js: it GETs the router's health endpoint (Accept: application/json) and, unless status is 200 with body exactly 'health is good', throws with the actual status and body. It is the readiness probe tests call before touching the environment under test.
Source
Thrown at cypress-tests/cypress/support/commands.js:602
Cypress.Commands.add("healthCheck", (globalState) => {
const baseUrl = globalState.get("baseUrl");
const url = `${baseUrl}/health`;
cy.request({
method: "GET",
url: url,
headers: {
Accept: "application/json",
},
}).then((response) => {
logRequestId(response.headers["x-request-id"]);
cy.wrap(response).then(() => {
if (response.status === 200) {
expect(response.body).to.equal("health is good");
} else {
throw new Error(
`Health Check failed with status: \`${response.status}\` and body: \`${response.body}\``
);
}
});
});
});
/**
* Creates a merchant account and optionally validates response fields.
* @param {Object} merchantCreateBody - The merchant creation request body
* @param {Object} globalState - The global state object
* @param {Object} options - Options for merchant creation
* @param {string|null} [options.expectedMerchantAccountType=null] - Expected merchant_account_type to validate (optional)
* @param {string} [options.expectedProductType="orchestration"] - Expected product_type to validate. Pass a string value like "vault", "recon", "recovery", etc. to validate the response contains this product_type. Defaults to "orchestration".
* @param {number} [options.expectedStatus=200] - Expected HTTP status code. Use 400 for negative test cases.
* @param {string} [options.expectedErrorCode=null] - Expected error code in response body (for negative test cases, e.g. "IR_06")
* @param {string} [options.merchantIdStateKey="merchantId"] - Key to store merchant ID in global state
* @param {string} [options.profileIdStateKey="profileId"] - Key to store profile ID in global stateView on GitHub (pinned to 9b8b89dc37)
Solutions
- Confirm the target service is up: curl <baseUrl>/health manually and expect 200 'health is good'
- Fix the baseUrl/port in globalState if it points at the wrong place (the body in the message usually reveals a proxy error page)
- In CI, add a readiness wait before invoking Cypress so healthCheck is a verification, not the first probe
- Check service logs for startup failures (DB unreachable, pending migrations) if health keeps failing
Example fix
// before
cy.healthCheck(url); // one-shot, throws while service boots
// after (retry until ready)
Cypress.Commands.add('healthCheckWithRetry', (url, attempts = 10) => {
const attempt = (n) =>
cy.request({ method: 'GET', url, failOnStatusCode: false }).then((response) => {
if (response.status === 200 && response.body === 'health is good') return;
if (n <= 1) {
throw new Error(`Health Check failed with status: ${response.status} and body: ${response.body}`);
}
cy.wait(3000).then(() => attempt(n - 1));
});
return attempt(attempts);
}); Defensive patterns
Strategy: retry
Validate before calling
// Probe readiness before the assertion-style healthCheck
cy.request({ method: 'GET', url: `${baseUrl}/health`, failOnStatusCode: false }).then((response) => {
if (response.status !== 200) {
throw new Error(`Service not ready (${response.status}); wait for deployment to finish before running tests`);
}
}); Try / catch
// Readiness-style retry around the strict one-shot check
Cypress.Commands.add('healthCheckWithRetry', (url, attempts = 10) => {
const attempt = (n) =>
cy.request({ method: 'GET', url, failOnStatusCode: false }).then((response) => {
if (response.status === 200 && response.body === 'health is good') return;
if (n <= 1) {
throw new Error(`Health Check failed with status: \`${response.status}\` and body: \`${response.body}\``);
}
cy.wait(3000).then(() => attempt(n - 1));
});
return attempt(attempts);
}); Prevention
- Add a CI readiness gate (curl /health loop) before Cypress starts
- Verify baseUrl/host/port in globalState when the failing body looks like a gateway page
- Expect exactly the body 'health is good' — a 200 with different body is still a failure
When it happens
Trigger: healthCheck runs while the router service is still starting, crashed, or misconfigured (DB/migrations pending) so /health returns 5xx; or the baseUrl in globalState points at the wrong host/port so the response is a proxy/gateway error page (status 404/502 with an HTML body).
Common situations: CI pipeline starts Cypress before the service is up (no readiness gate); local run against a stopped container; port mismatch after a compose change; k8s liveness not yet passing during rollout; smoke tests against an environment mid-deploy.
Related errors
- Failed to fetch QR code image: ${response.statusText}
- Unsupported connector: ${connectorId}
- Unsupported payment method type: ${payment_method_type}
- Please provide a baseUrl
- Unsupported baseUrl
AI-assisted analysis of juspay/hyperswitch@9b8b89dc37 (2026-08-16).
Data as JSON: /api/errors/c28e7787b5956197.
Report an issue: GitHub.