supabase/supabase · error

error.message

Error message

error.message

What it means

Passthrough of supabase-js storage.vectors.from(id).listIndexes() error as a 500. The route calls listIndexes({ maxResults: 100 }) and, on success, fans out to getIndex(indexName) for each result via Promise.all to enrich. Because the error is mapped to 500, even client-shaped causes (wrong bucket id, vectors disabled) look like server faults. The fan-out also means a single getIndex failure would throw an unhandled rejection rather than hit this branch.

Source

Thrown at apps/studio/pages/api/platform/storage/[ref]/vector-buckets/[id]/indexes/index.ts:31

    case 'GET':
      return handleGet(req, res)
    case 'POST':
      return handlePost(req, res)

    default:
      res.setHeader('Allow', ['GET', 'POST'])
      res.status(405).json({ data: null, error: { message: `Method ${method} Not Allowed` } })
  }
}

const handleGet = async (req: NextApiRequest, res: NextApiResponse) => {
  const { id } = req.query

  const { data, error } = await supabase.storage.vectors
    .from(id as string)
    .listIndexes({ maxResults: 100 })

  if (error) return res.status(500).json({ error: { message: error.message } })

  const indexes = await Promise.all(
    data.indexes.map(async ({ indexName }) => {
      return (await supabase.storage.vectors.from(id as string).getIndex(indexName)).data?.index
    })
  )

  return res.status(200).json({ indexes, nextToken: data.nextToken })
}

const handlePost = async (req: NextApiRequest, res: NextApiResponse) => {
  const { id } = req.query
  const { indexName, dataType, dimension, distanceMetric, metadataKeys } = req.body
  const payload = {
    indexName,
    dataType,
    dimension,
    distanceMetric,

View on GitHub (pinned to beee91b9c2)

Solutions

  1. Read the underlying error from server logs — the 500 message is the raw listIndexes error.
  2. Confirm the bucket id exists and vectors are enabled on storage-api.
  3. Guard the Promise.all fan-out: wrap each getIndex in allSettled so one failing index doesn't sink the whole list.
  4. Verify SUPABASE_SERVICE_KEY/SUPABASE_URL and storage-api health.

Example fix

// before
const indexes = await Promise.all(
  data.indexes.map(async ({ indexName }) => {
    return (await supabase.storage.vectors.from(id).getIndex(indexName)).data?.index
  })
)
// after — tolerate partial failures
const results = await Promise.allSettled(
  data.indexes.map(({ indexName }) =>
    supabase.storage.vectors.from(id).getIndex(indexName).then((r) => r.data?.index)
  )
)
const indexes = results.filter((r) => r.status === 'fulfilled').map((r) => r.value)
Defensive patterns

Strategy: fallback

Validate before calling

// server-side guard against the fan-out throwing
// (no client-side prevention for a 500 here)

Try / catch

try {
  const res = await fetch(url, { method: 'GET' })
  if (res.status === 500) throw new Error('Vector index listing failed; check storage-api and bucket id')
} catch (e) { /* retry or surface */ }

Prevention

When it happens

Trigger: GET .../vector-buckets/[id]/indexes where the bucket does not exist, vectors are not enabled on storage-api, the admin key is wrong, or one of the inner getIndex calls rejects (which would crash the handler, not return this 500).

Common situations: Studio ahead of storage-api (no vectors support); bucket id typo; storage-api down; network blip during the fan-out enrichment causing a partial failure.

Related errors


AI-assisted analysis of supabase/supabase@beee91b9c2 (2026-08-12). Data as JSON: /api/errors/0b353bf2a9f62e99. Report an issue: GitHub.