## TL;DR
If cy.session() replays the login before every test, either validation keeps failing or the session is not cached where you expect. Fix the validate function first, then set cacheAcrossSpecs when specs should share. A session that validates cleanly is a session Cypress reuses.

## Error
```text
CypressError: cy.session() could not validate the stored session.

The validate function did not pass, so the session was discarded
and the setup function ran again before the test.
```

## Steps
1. Run one spec and watch whether login executes before every test or just the first. Expected: you can see the repeat behavior directly.
2. Test the validate function by hand: log in once, then run its assertions in the Cypress runner. Expected: every assertion in validate passes while logged in.
3. Write validate against a stable logged-in indicator on a page you visit first:
```js
Cypress.Commands.add('login', function() {
  cy.session('user-session', function() {
    cy.visit('/login')
    cy.get('[data-cy=username]').type('ada')
    cy.get('[data-cy=password]').type('[your value]', { log: false })
    cy.get('[data-cy=submit]').click()
    cy.url().should('include', '/dashboard')
  }, {
    validate: function() {
      cy.visit('/dashboard')
      cy.get('[data-cy=user-menu]').should('be.visible')
    },
    cacheAcrossSpecs: true,
  })
})
```
Expected: setup ends on a logged-in page and validate checks one visible element there.
4. If specs should share the login, keep cacheAcrossSpecs true. If each spec must log in fresh, set it false and expect the replay. Expected: the caching behavior matches what you intended.
5. Remember testIsolation true clears page state between tests but restores the session cookies and storage. Expected: no test depends on DOM state from a previous test.
6. Re-run the suite. Expected: login runs once, then tests reuse the session.

## When to use
- Every test replays the full login flow instead of reusing cy.session()
- The session works in the first spec but not the second
- Login recently moved into a custom command

## When not to use
- Login itself fails (fix the login flow first)
- You manage cookies by hand without cy.session() (a different pattern)
- API tests that never touch the browser (sessions are a browser concept)

## Tool compatibility
- Cypress 12 through 14, cy.session() and testIsolation
- Cookie, localStorage, and sessionStorage based logins
- Chrome, Edge, Firefox, and Electron runners

## Variant phrasings
### Cypress session not shared between spec files
That is cacheAcrossSpecs defaulting to false. Set it true on the cy.session() call that defines the login.
### cy.session validate keeps failing
Validate runs against the current page state. Visit a logged-in page inside validate before asserting.

## Why it happens
cy.session() stores cookies and storage after setup, then runs validate before each test to confirm the session is still good. If validate fails, Cypress throws the session away and replays setup. Without cacheAcrossSpecs, each spec file starts with an empty session cache by design.

## Edge cases
- Validate passes locally but fails in CI: the logged-in indicator may render slower in CI. Add a retry-friendly assertion, not a fixed sleep.
- Session persists but the app logs the user out: short server-side session expiry. Refresh the token in validate or lengthen expiry in the test environment.
- Multiple users in one suite: give each cy.session() a unique id so sessions do not overwrite each other.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_4PQDM4lNTlPQVaWhBqLaiw
