Replies: 2 comments
-
|
This looks like the previous failed storage request is leaving something open in the Bun runtime/client connection state, rather than RLS itself “blocking” the next test. A policy-denied upload should come back as a normal Storage API error, usually The first thing worth isolating is whether the hang is tied to reusing the same afterEach(async () => {
await supabase.auth.signOut()
// Give Bun a chance to close pending fetch/body work between tests.
await new Promise((resolve) => setTimeout(resolve, 0))
})Also make sure the denied upload is not accidentally leaving a promise unobserved. The denied request should be awaited and asserted directly: const { data, error } = await supabase.storage
.from('user_profiles')
.upload(`${otherUserId}/${imageName}`, imageContent)
expect(data).toBeNull()
expect(error).not.toBeNull()If the next upload still hangs, try creating a completely new Supabase client after the denied upload rather than only signing out: afterEach(async () => {
await supabase.auth.signOut()
supabase = undefined as any
})And in each test: beforeEach(() => {
supabase = createSupabaseClient()
})One important thing in this test setup: avoid sharing the same storage object path across tests. If two tests generate const imageName = `test-image-${crypto.randomUUID()}.jpg`For the RLS test specifically, I would also verify that the policy is denying at the A useful workaround to confirm the connection-reuse theory is to inject a fetch implementation that does not reuse state between requests, or at least add a timeout wrapper around the storage call so the test fails with context instead of hanging forever: async function withTimeout<T>(promise: Promise<T>, ms = 10_000): Promise<T> {
const timeout = new Promise<never>((_, reject) =>
setTimeout(() => reject(new Error(`Timed out after ${ms}ms`)), ms)
)
return Promise.race([promise, timeout])
}
const { data, error } = await withTimeout(
supabase.storage
.from('user_profiles')
.upload(`${userId}/${imageName}`, imageContent),
)The snippet is cut off at
If my answer solved your problem, you can click answered the question. I'm really here to help, and along the way I'm also collecting Galaxy Brain badges haha 😆 |
Beta Was this translation helpful? Give feedback.
-
|
The "a previous RLS-denied upload makes a later upload hang" pattern almost always points at the HTTP transport rather than Storage itself — specifically an error response whose body never gets drained, leaving a keep-alive socket in a bad state that the next request then blocks on. Bun's When the RLS check denies the upload, storage-js gets a non-2xx response. If that error body isn't fully consumed, the underlying connection can be reused in a half-read state, and the next upload on that connection just sits there. A signed-out client in Things worth trying, roughly in order:
If it turns out to reproduce under Node too, then it's more likely the self-hosted Storage API (or rustFS) holding a lock on the object key after the denied attempt — in that case the storage container logs around the denied request vs. the hung one would be the next thing to compare. Do you see it under Node/vitest, or only Bun? |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Storage upload hangs in later Bun test after previous RLS-denied upload (self-hosted Supabase)
Environment
Full test file
Issue
I have a storage test suite where one test intentionally triggers an RLS violation by attempting to upload into another user's folder.
If that test runs before another storage upload test, the later upload hangs indefinitely.
The hang occurs on (3rd test case):
The promise never resolves and the test eventually times out.
Important observation
The behavior depends on test order.
Current order:
Result:
storage.upload()However, if I move test 2 ("should not allow uploading to another user's folder") to the bottom of the file:
Then all tests pass.
This makes me suspect either:
Additional notes
beforeEach()did not resolve the issue.Has anyone encountered this behavior before, or is there anything specific I should inspect in the Storage/Auth logs to determine whether this is a client-side issue or a self-hosted Storage issue?
I can also provide other informations as needed.
Beta Was this translation helpful? Give feedback.
All reactions