Nuxt.js

How to Solve the Nuxt.js Composable Access Error (TypeScript)

How to Solve the Nuxt.js Composable Access Error (TypeScript)

While working on a Nuxt.js 3 project with Supabase authentication, I ran into a confusing error that had me scratching my head for longer than I’d like to admit.

I was trying to refresh a session via a composable, then use it inside middleware which should be valid… except Nuxt yelled at me:

[nuxt.js] A composable that requires access to the Nuxt instance was called outside of a plugin, Nuxt hook, Nuxt middleware, or Vue setup function.

Let me walk you through the issue, the cause, and how I fixed it plus a few best practices to make your middleware even more reliable.

The Problem Invalid Composable Structure

Here’s the original code that triggered the issue.

/middleware/org.ts

export default defineNuxtRouteMiddleware(async () => {
  const newSession = await useNewSession() // ERROR TRIGGERS HERE
  const accessToken = newSession.access_token

  const { data, error } = await useFetch('/api/organization', {
    headers: {
      authorization: `Bearer ${accessToken}`
    }
  })

  if (error.value) {
    throw error
  }

  const organizationCookie = useCookie('organization')
  organizationCookie.value = JSON.stringify(data.value)
})

/composables/useNewSession.ts

export default async function() {
  const supabase = useNuxtApp().$supabase
  const { data, error } = await supabase.auth.refreshSession()

  if (error || !data.session) {
    navigateTo('/login')
    const toast = useToast()
    toast.add({
      title: 'Session error',
      description: error?.message,
      color: 'error',
    })
    throw error
  }

  return data.session
}

Why Nuxt Throws This Error

Even though I called the function inside middleware, Nuxt.js still rejected it because:

  • A valid composable must:
    • Start with use...
    • Be a pure function, not something that triggers navigation or toasts internally
    • Preferably be synchronous in structure, even if it returns a Promise

Because I exported async function () { ... } as default, Nuxt didn’t treat it as a composable it treated it like a regular utility function, which caused the warning.

The Fix: Make It a Proper Composable & Move Logic to Middleware

Here’s how I rewrote it.

/composables/useNewSession.ts (Fixed)

export const useNewSession = async () => {
  const supabase = useNuxtApp().$supabase
  const { data, error } = await supabase.auth.refreshSession()

  return { session: data?.session, error }
}

/middleware/org.ts (Improved)

export default defineNuxtRouteMiddleware(async () => {
  const { session, error } = await useNewSession()

  if (!session || error) {
    const toast = useToast()
    toast.add({
      title: 'Session expired',
      description: 'Please log in again.',
      color: 'error',
    })
    return navigateTo('/login')
  }

  const accessToken = session.access_token

  const { data, error: orgError } = await useFetch('/api/organization', {
    headers: { authorization: `Bearer ${accessToken}` }
  })

  if (orgError.value) throw orgError

  useCookie('organization').value = JSON.stringify(data.value)
})

Now everything works perfectly no warnings, clean logic separation, and a much more reusable pattern.

Bonus Improvements I Plan to Add

Feature IdeaDescription
Token expiry checkIf the access token expires in less than X minutes, refresh proactively
Retry logicIf /api/organization fails once, try again before throwing
Session timestamp loggingStore last refresh time in localStorage or cookie
Global loading indicatorShow a spinner while middleware is running on route change

Final Thoughts

This error wasn’t really about where I used the composable it was about how I structured it. Nuxt.js expects composables to stay pure and free of side effects, and once I moved navigation and UI handling out of the composable and into the middleware, everything fell into place. A small refactor made my code cleaner, more reusable, and much easier to maintain. If you hit this issue too, don’t worry it’s an easy fix once you understand the pattern.

Zhexuan Liu

About Zhexuan Liu

Zhexuan Liu is a seasoned full-stack developer with over 9 years of experience in crafting robust applications. Specializing in Nuxt.js development, he has delivered high-performance solutions for both front-end and back-end applications.

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments