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
- Read the underlying error from server logs — the 500 message is the raw listIndexes error.
- Confirm the bucket id exists and vectors are enabled on storage-api.
- Guard the Promise.all fan-out: wrap each getIndex in allSettled so one failing index doesn't sink the whole list.
- 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
- Replace Promise.all with Promise.allSettled in the route's fan-out so one bad index doesn't sink the list
- Confirm vectors are enabled on storage-api before calling
- Keep the bucket id validated
- Add server-side logging of the raw listIndexes error
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.