juspay/hyperswitch · error · Error
User login call failed to fetch user info with status: "${re
Error message
User login call failed to fetch user info with status: "${response.status}" and message: "${response.body.error.message}" What it means
Thrown by userInfo when GET /user (Authorization: Bearer {userInfoToken}) responds non-200. The user_info token is short-lived, so 401 expiry is the most common cause; 403/404 typically indicate the token lacks scope or the user record is gone.
Source
Thrown at cypress-tests/cypress/support/commands.js:6957
}).then((response) => {
logRequestId(response.headers["x-request-id"]);
cy.wrap(response).then(() => {
if (response.status === 200) {
expect(response.body, "merchant_id").to.have.property("merchant_id").and
.to.not.be.empty;
expect(response.body, "organization_id").to.have.property("org_id").and
.to.not.be.empty;
expect(response.body, "profile_id").to.have.property("profile_id").and
.to.not.be.empty;
globalState.set("merchantId", response.body.merchant_id);
globalState.set("organizationId", response.body.org_id);
globalState.set("profileId", response.body.profile_id);
globalState.set("userInfoToken", userInfoToken);
} else {
throw new Error(
`User login call failed to fetch user info with status: "${response.status}" and message: "${response.body.error.message}"`
);
}
});
});
});
// Specific to routing tests
Cypress.Commands.add("ListMcaByMid", (globalState) => {
const merchantId = globalState.get("merchantId");
cy.request({
method: "GET",
url: `${globalState.get("baseUrl")}/account/${merchantId}/connectors`,
headers: {
"Content-Type": "application/json",
"api-key": globalState.get("apiKey"),
"X-Merchant-Id": merchantId,
},View on GitHub (pinned to 9b8b89dc37)
Solutions
- Re-run the whole login chain (userLogin → terminate2Fa → userInfo) immediately before any step that needs merchantId/profileId
- Confirm terminate2Fa succeeded and set userInfoToken (see error 69)
- Check x-request-id in server logs to distinguish expiry (401) from authorization (403)
- Verify globalState baseUrl matches the environment the user belongs to
Example fix
// before (stale token reused) cy.userInfo(globalState); // after cy.userLogin(globalState); cy.terminate2Fa(globalState); cy.userInfo(globalState);
Defensive patterns
Strategy: retry
Validate before calling
// refresh the user_info token if it may be stale
const issuedAt = globalState.get('userInfoTokenIssuedAt');
if (!globalState.get('userInfoToken') || isOlderThanMinutes(issuedAt, 10)) {
cy.userLogin(globalState);
cy.terminate2Fa(globalState);
}
cy.userInfo(globalState); Try / catch
cy.wrap(null)
.then(() => cy.userInfo(globalState))
.catch((e) => {
if (/fetch user info with status: "401"/.test(e.message)) {
// token expired mid-run: re-authenticate once and retry
cy.userLogin(globalState);
cy.terminate2Fa(globalState);
return cy.userInfo(globalState);
}
throw e;
}); Prevention
- Do the login chain as late as possible, right before the first use of merchantId/profileId
- Re-authenticate in a beforeEach for long specs instead of once in a before
- Distinguish 401 (expired token) from 403 (permissions) in the catch so retries do not mask real issues
When it happens
Trigger: Long gap between terminate2Fa and userInfo so the bearer token expired (401); token invalid because terminate2Fa actually failed; user deleted or permissions changed mid-run; wrong baseUrl hitting another environment.
Common situations: Slow CI or many setup steps between login and /user call; reusing a recorded token across retries; environment mismatch (local token against staging).
Related errors
- User login call failed to get totp token with status: "${res
- No token received from login
- No user info token available
- Blocklist create rule failed with status: ${response.status}
- Blocklist delete failed with status: ${response.status} and
AI-assisted analysis of juspay/hyperswitch@9b8b89dc37 (2026-08-16).
Data as JSON: /api/errors/e56be1caafc43c6e.
Report an issue: GitHub.