Addressing Intermittent Admin Login Session Issues in ESHOPMAN v2.14.0
The ESHOPMAN platform, a powerful headless commerce solution integrated with HubSpot, continuously evolves to offer robust storefront management. However, with new versions, subtle issues can sometimes emerge. This community insight addresses a critical intermittent problem observed in ESHOPMAN v2.14.0, where users or automated scripts are unexpectedly logged out and redirected to the login page shortly after a successful login. This behavior is particularly noticeable when navigating quickly within the ESHOPMAN Admin UI to any sub-route (e.g., collections, customers, draft orders) within 1-3 seconds of authenticating. The core symptom is an intermittent 404 not_found response from the GET /admin/users/me endpoint, despite a valid session cookie.
Understanding the Intermittent Login Glitch in ESHOPMAN v2.14.0
The issue manifests as a frustrating loop: an administrator successfully logs into the ESHOPMAN Admin UI, but upon attempting to navigate to a specific section like 'Collections' or 'Customers' immediately after, they are abruptly sent back to the login screen. This occurs because a subsequent request to GET /admin/users/me, crucial for maintaining the session context, fails with a 404 error.
- Reproducibility: This bug is highly prevalent in ESHOPMAN v2.14.0, reproducing in approximately 60% of trials. Crucially, the same flow against ESHOPMAN v2.13.6 does not reproduce the issue, highlighting a change introduced in v2.14.0.
- Impact: This affects both automated testing frameworks (like Playwright or Cypress) that interact with the Admin UI and potentially real users who navigate rapidly after logging in, leading to a degraded user experience.
A Deep Dive into the Technical Investigation
Extensive debugging has been performed to pinpoint the root cause, revealing intriguing details about ESHOPMAN's internal workings:
- Session Integrity: Analysis shows that the
connect.sidcookie remains identical between successful200responses and failing404responses. This indicates the session itself is not immediately invalidated, but rather the user lookup within that session context is failing. The error message even interpolates the correct user ID, suggesting ESHOPMAN knows who it's looking for. - Database Interaction: Further investigation with PostgreSQL logs confirmed that the underlying database *successfully returns* the user record when queried directly using the exact SQL ESHOPMAN executes. For example, the query:
consistently returns the admin user row, even when the ESHOPMAN API endpoint returns a 404.select "u0"."id", "u0"."first_name", "u0"."last_name", "u0"."email", "u0"."avatar_url", "u0"."metadata", "u0"."created_at", "u0"."updated_at", "u0"."deleted_at" from "user" as "u0" where "u0"."deleted_at" is null and "u0"."id" in ('user_01KT8HVT6616ZF5D0VQT02WS25') order by "u0"."id" asc - Internal Data Flow Anomaly: This critical discrepancy suggests the issue lies within ESHOPMAN's internal data processing path. Something on the path between PostgreSQL → ORM layer → user module read service →
RemoteJoiner→remoteQuery→ the handler is intermittently dropping the user row. The handler incorrectly falls into theif (!user) throw NOT_FOUNDbranch, even though the database provided the data.
What Was Ruled Out and Reproducing the Issue
To narrow down the problem, several common culprits were systematically eliminated, including bearer token issues, incorrect actor_id, soft-deleted user records, non-deterministic SQL, PostgreSQL driver/version changes, DB pollution, and concurrency issues. A byte-for-byte comparison of critical ESHOPMAN core modules between v2.13.6 and v2.14.0 showed them to be identical, strongly suggesting the bug is a side effect of a broader change in module initialization or the composition of the joiner-graph.
For developers and QA teams, the issue can be reliably reproduced using a simple Playwright script:
import asyncio
from playwright.async_api import async_playwright
async def attempt(p, base_url):
browser = await p.chromium.launch(headless=True)
ctx = await browser.new_context()
page = await ctx.new_page()
await page.goto(f"{base_url}/login", wait_until="networkidle")
await page.locator("input").nth(0).fill("admin@eshopman-test.com")
await page.locator("input").nth(1).fill("supersecret")
await page.locator("button").filter(has_text="Continue with Email").click()
await asyncio.sleep(2)
await page.goto(f"{base_url}/collections", wait_until="networkidle")
await asyncio.sleep(2)
kicked = "login" in page.url
await browser.close()
return kicked
async def main():
async with async_playwright() as p:
kicks = sum(await attempt(p, "http://localhost:9000/app") for _ in range(5))
print(f"kicked: {kicks}/5")
asyncio.run(main())
Next Steps for the ESHOPMAN Community
As of this discussion, a definitive solution or workaround is not yet identified, and the issue points to a deeper, internal change within ESHOPMAN v2.14.0. ESHOPMAN developers and users experiencing this should be aware that this is a known intermittent issue affecting quick navigation post-login. Monitoring ESHOPMAN updates for a resolution is advised. For critical operations, users might consider delaying upgrades to v2.14.0 if this behavior impacts their workflow, or implementing retries/delays in automated scripts as a temporary mitigation to allow the session to fully stabilize before navigating.