moeru-ai/airi · error · Error

voice packs upstream ${res.status}: ${await res.text().catch

Error message

voice packs upstream ${res.status}: ${await res.text().catch(() => '')}

What it means

load() calls authedFetch GET ${SERVER_URL}/api/v1/voice-packs; any non-OK status throws with the HTTP code plus up to 256 chars of the response body. The store catches it into error.value and empties packs, so the failure surfaces via store state rather than an unhandled rejection.

Source

Thrown at packages/stage-ui/src/stores/voice-packs.ts:50

 * - The user is authenticated; {@link authedFetch} refreshes an expired access
 *   token once before surfacing the response.
 *
 * Returns:
 * - Reactive list/error/loading state plus a `load()` action.
 */
export const useVoicePacksStore = defineStore('voice-packs', () => {
  const packs = ref<VoicePackListItem[]>([])
  const loading = ref(false)
  const error = ref<string | null>(null)

  async function load() {
    loading.value = true
    error.value = null

    try {
      const res = await authedFetch(new URL('/api/v1/voice-packs', SERVER_URL))
      if (!res.ok)
        throw new Error(`voice packs upstream ${res.status}: ${await res.text().catch(() => '')}`.slice(0, 256))

      const data = await res.json() as VoicePackListItem[]
      packs.value = data
      return data
    }
    catch (err) {
      error.value = errorMessageFrom(err) ?? 'Unknown error'
      packs.value = []
      return []
    }
    finally {
      loading.value = false
    }
  }

  return { packs, loading, error, load }
})

View on GitHub (pinned to 677329427f)

Solutions

  1. If 401/403: re-authenticate, then call load() again.
  2. Confirm SERVER_URL resolves to an API that serves /api/v1/voice-packs (curl it directly).
  3. Read the sliced body embedded in error.value for the backend's own error detail.
  4. If 5xx or unreachable: start or restart the server stack under server/.
Defensive patterns

Strategy: retry

Validate before calling

if (!authStore.user) {
  await authClient.getSession() // refresh session before an authed fetch
}

Try / catch

const packs = await voicePacksStore.load()
if (voicePacksStore.error?.includes(' 401')) {
  await authClient.getSession()
  await voicePacksStore.load() // single retry after re-auth
}

Prevention

When it happens

Trigger: 401/403 when the auth session expired or authedFetch attached no valid token; 404 when SERVER_URL points at a backend without the voice-packs route; 5xx when the API server is down or erroring.

Common situations: Long-idle tab with an expired session; dev SERVER_URL env pointing at the wrong origin; frontend deployed against an older API build; the server/ docker-compose stack not started.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18). Data as JSON: /api/errors/d88c42bd36948d8b. Report an issue: GitHub.