Skip to content

[Bug]: beforeOpen is called twice during link navigation #53

Description

@sergeysova

Package

@effector/router (core)

What happened?

When a route that has a beforeOpen handler is opened through the public open API (which is exactly what <Link> does under the hood), the beforeOpen effects run twice for a single navigation. During the extra pending window the route is briefly not $isOpened, which surfaces a spurious "404" flash before the page settles.

Expected: beforeOpen should run exactly once per navigation, and the route should not flash an unopened/404 state.

Sequence that causes the duplicate:
route.open() runs openFx (beforeOpen 1) → on openFx.done the router pushes the location → locationUpdatedopenRoutesByPathFx re-triggers the route via navigatednavigatedFx (attach({ effect: openFx })) runs openFx again (beforeOpen 2).

This is inherited from the predecessor project — see the original report: movpushmov/argon-router#30

Reproduction

const beforeOpenFn = vi.fn();

const profile = createRoute({
  path: '/profile',
  beforeOpen: [createEffect(beforeOpenFn)],
});
const feed = createRoute({ path: '/' });

const router = createRouter({ routes: [feed, profile] });
const history = createMemoryHistory();

await allSettled(router.setHistory, { scope, params: historyAdapter(history) });

// `<Link to={routes.profile}>` navigation is `route.open()`.
await allSettled(profile.open, { scope, params: {} });

expect(beforeOpenFn).toBeCalledTimes(1); // fails: called 2 times

A failing reproduction test is added in packages/core/tests/issue-30-before-open-called-twice.test.ts.

Steps in the original app repro:

  1. Route with an async beforeOpen effect on /profile.
  2. Click a <Link> to that route.
  3. Observe the beforeOpen effect logs twice and a 404 page flashes during the transition.

Environment

  • @effector/router: 1.1.0
  • effector: >=23
  • node: 24.x

Metadata

Metadata

Assignees

Type

Fields

No fields configured for Bug.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions