Skip to content

Composables Issues

This page covers missing exports, bad imports, reactive pitfalls, and callback confusion in the generated client layer.

Composable is missing

Most often one of these is true:

  • the matching generator is not enabled
  • the composable name is based on a different operationId
  • the app is importing from an old path

Current generated output lives under openapi/composables/ by default.

Examples:

text
openapi/composables/use-async-data/
openapi/composables/use-fetch/
openapi/composables/connectors/

If a folder is missing, verify openapi.generators first.

ts
export default defineNuxtConfig({
  modules: ['nuxt-openapi-hyperfetch'],
  openapi: {
    input: './swagger.yaml',
    generators: ['useFetch', 'useAsyncData'],
    enableAutoImport: true,
  },
})

Import path is wrong

Use either auto-imported composables, or import from the generated openapi/ tree.

ts
import { useAsyncDataGetPetById } from '~/openapi/composables/use-async-data'
import type { GetPetByIdData, Pet } from '~/openapi'

If auto-import is enabled, you can call the composable directly without importing it manually.

Export name is different than expected

Composable names are derived from the OpenAPI operationId.

For example, an operation with operationId: getPetById generates names like:

ts
useAsyncDataGetPetById
useAsyncDataGetPetByIdRaw
useFetchGetPetById
useFetchGetPetByIdRaw

If you expected shorter resource-based names, inspect the actual generated index first.

useAsyncData composable does not accept the parameters you passed

Generated useAsyncData composables do not take a custom fetch handler. They wrap the request for you.

This is wrong for the current generator output:

ts
useAsyncDataPets('pets', async () => {
  return await $fetch('/api/pets')
})

Use the generated signature instead:

ts
const params = computed<GetPetByIdData>(() => ({
  path: {
    petId: Number(route.params.id),
  },
}))

const { data, error } = useAsyncDataGetPetById(params)

Many generated composables also support a custom cache key as the first argument.

ts
const { data } = useAsyncDataGetPetById('pet-detail', {
  path: { petId: 1 },
})

Reactive params do not trigger a refresh

Pass a ref or computed, not a frozen snapshot.

ts
const petId = ref(1)

const params = computed<GetPetByIdData>(() => ({
  path: { petId: petId.value },
}))

const { data } = useAsyncDataGetPetById(params)

petId.value = 2

If you pass a plain object created once, the request will not react to later state changes.

Auto-imports do not work

Auto-import depends on both module setup and generation output.

Check all of these:

  1. enableAutoImport is not false
  2. the relevant generator is enabled
  3. generation actually ran for the current command
  4. the app was restarted after a large output layout change

If needed, import from ~/openapi/composables/... directly to confirm the generated file exists.

Data is always undefined

When a generated composable returns no data, usually the request itself failed.

Inspect the error state before assuming the composable is broken.

ts
const { data, error, status } = useAsyncDataGetPetById({
  path: { petId: 1 },
})

console.log(status.value)
console.log(error.value)

The most common root cause is a missing base URL:

ts
export default defineNuxtConfig({
  runtimeConfig: {
    public: {
      apiBaseUrl: process.env.NUXT_PUBLIC_API_BASE_URL || 'https://api.example.com',
    },
  },
})

You can also pass baseURL per call.

Global headers are not applied

The runtime looks for global headers in one of these forms:

  1. a user composable named useApiHeaders()
  2. a Nuxt plugin that provides $getApiHeaders

Example composable:

ts
export const useApiHeaders = () => () => {
  const token = useCookie('token')

  return token.value
    ? { Authorization: `Bearer ${token.value}` }
    : {}
}

If your app uses another name, generated requests will not see it automatically.

Global callbacks are not firing

The runtime reads global callback rules from a Nuxt plugin that provides getGlobalApiCallbacks.

ts
export default defineNuxtPlugin(() => {
  const globalCallbacks = [
    {
      onError: (error: unknown) => {
        console.error(error)
      },
    },
  ]

  return {
    provide: {
      getGlobalApiCallbacks: () => globalCallbacks,
    },
  }
})

If your plugin provides another property name, the runtime will ignore it.

Local callback never runs

Check both the local callback and the global callback chain.

  • a failing request will skip local success handling
  • a global callback may intentionally stop later execution
  • the operation may be returning an error payload you are not logging yet

Start by logging error.value and keeping the local callback minimal.

SSR output does not match the browser

Hydration issues are usually rendering issues, not generator issues.

Render a stable loading state before using the data.

vue
<script setup lang="ts">
const { data, pending } = useAsyncDataGetPetById({
  path: { petId: 1 },
})
</script>

<template>
  <div v-if="pending">Loading...</div>
  <div v-else-if="data">{{ data.name }}</div>
</template>

Checklist

When a generated composable looks broken, verify in this order:

  1. the required generator is enabled
  2. generation output exists under openapi/composables/
  3. the export name matches the real operationId
  4. imports use the generated openapi/ tree or auto-import
  5. runtimeConfig.public.apiBaseUrl is set, or baseURL is passed manually
  6. global headers and callbacks use the exact names the runtime reads

Released under the Apache-2.0 License.