Skip to content

fix: invalidate API route handler cache on file changes - #406

Merged
kwakayama merged 2 commits into
mainfrom
fix/api-route-handler-cache-invalidation
Feb 20, 2026
Merged

fix: invalidate API route handler cache on file changes#406
kwakayama merged 2 commits into
mainfrom
fix/api-route-handler-cache-invalidation

Conversation

@kwakayama

Copy link
Copy Markdown
Contributor

Summary

  • Fix stale API routes after file edits/deploys in proxy/production mode
  • Fix 404s for new API routes that were only discovered during initialize() which never re-ran

Root Cause

invalidateProjectCaches() clears SSR caches, module caches, renderer caches, and snippet caches — but never destroys the cached APIRouteHandler instance. In local dev mode this works because invalidateRuntimeHandler() calls resetApiHandler() directly, but in proxy/production mode the handler cache was never touched.

Changes

  • pages-api-handler.ts: Add resetApiHandlerForProject(projectSlug) — iterates the handler cache and destroys entries matching the project slug (handles both ${projectDir}:${projectSlug} proxy keys and plain slug keys). Add entries() to HandlerCache interface.
  • cache-invalidation.ts: Call resetApiHandlerForProject(projectSlug) inside invalidateProjectCaches() alongside existing cache clears.

Test plan

  • Existing unit tests pass (tests/server/context/cache-invalidation.test.ts)
  • Existing integration tests pass (tests/integration/core/api-handler.test.ts, tests/integration/adapters/cache-invalidation.test.ts)
  • Full typecheck passes (pre-commit hook)
  • Manual: edit an API route in Studio, verify preview immediately reflects the change
  • Manual: create a new API route, verify it's accessible without pod restart
  • Manual: Deploy, verify production reflects the change

The compiled API route handler cache was never cleared during
invalidateProjectCaches(), causing stale handlers in proxy/production
mode after file edits or deploys, and 404s for newly created API routes.
Copilot AI review requested due to automatic review settings February 20, 2026 15:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes stale Pages Router API route behavior in proxy/production by ensuring cached APIRouteHandler instances are invalidated when project files change, so route discovery/initialization is re-run after edits/deploys.

Changes:

  • Add resetApiHandlerForProject(projectSlug) to selectively destroy cached API handlers for a given project slug.
  • Extend the HandlerCache injection interface to support iterating cache entries.
  • Invoke API handler invalidation as part of invalidateProjectCaches().

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/server/handlers/request/api/pages-api-handler.ts Adds per-project API handler cache reset by iterating cache entries and destroying matching handlers.
src/server/handlers/request/api/index.ts Re-exports the new resetApiHandlerForProject helper.
src/server/context/cache-invalidation.ts Calls resetApiHandlerForProject(projectSlug) during per-project cache invalidation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +106 to +108
logger.debug("Clearing API route handler cache (per-project)", { projectSlug });
await resetApiHandlerForProject(projectSlug);

Copilot AI Feb 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

invalidateProjectCaches() is invoked in a fire-and-forget way (e.g. from the HMR ReloadNotifier callback), so any rejection here becomes an unhandled promise rejection. Adding another awaited step (resetApiHandlerForProject) increases the surface area for that. Consider wrapping the per-project invalidation sequence in a top-level try/catch (logging and swallowing), or ensuring all call sites await/.catch() the returned promise so failures don't crash the process or get dropped silently.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed — wrapped the resetApiHandlerForProject call in a try/catch that logs and swallows (47c4970).

Tests slug suffix matching, exact key matching, multi-entry cleanup,
no-match safety, and partial-suffix rejection. Also wraps the
resetApiHandlerForProject call in try/catch per review feedback.
@kwakayama
kwakayama merged commit 36f3271 into main Feb 20, 2026
13 checks passed
@kwakayama
kwakayama deleted the fix/api-route-handler-cache-invalidation branch February 20, 2026 15:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants