supabase-swift icon indicating copy to clipboard operation
supabase-swift copied to clipboard

_invokeWithStreamedResponse does not return any Data when throwing a httpError

Open bbauman1 opened this issue 1 year ago • 3 comments

Bug report

  • [x] I confirm this is a bug with Supabase, not with my own application.
  • [x] I confirm I have searched the Docs, GitHub Discussions, and Discord.

Describe the bug

Understand that this function is marked experimental but creating an issue to track that when an httpError is thrown the Data object is always empty. I tried coming up with a fix here but it didn't seem to work. https://github.com/bbauman1/supabase-swift/commit/43d9f01d185b66ba5edc40d403499ad7b8794cf9

Also, lesser important, but the completionHandler doesn't always get called which leads to an error in Xcode logs

To Reproduce

Call _invokeWithStreamedResponse and have it throw an error

Expected behavior

Data object is not empty

Screenshots

If applicable, add screenshots to help explain your problem.

System information

  • OS: [e.g. macOS, Windows]
  • Browser (if applies) [e.g. chrome, safari]
  • Version of supabase-js: [e.g. 6.0.2]
  • Version of Node.js: [e.g. 10.10.0]

Additional context

Add any other context about the problem here.

bbauman1 avatar Jan 09 '25 21:01 bbauman1

My issue might be related as well - when calling client.functions._invokeWithStreamedResponse how am I expected to handle errors? While streaming them seems to be what is implied here, I'm not sure it's the correct approach. Sending errors with the traditional HTTP code leads to API MISUSE: NSURLSession delegate Functions.StreamResponseDelegate: <Functions.StreamResponseDelegate: 0x3008e57c0> (0x3008e57c0) API MISUSE: dataTask:didReceiveResponse:completionHandler: completion handler not called

cyrilzakka avatar Feb 23 '25 03:02 cyrilzakka

Hi @cyrilzakka do you have an example edge functions for reproducing it?

grdsdev avatar Feb 24 '25 10:02 grdsdev

Sure! Here's a minimally reproducible example:

Deno.serve(async (req) => {
  [...]

  try {
    // Get authorization header
    const authHeader = req.headers.get('Authorization');
    if (!authHeader) {
      throw new Error('Missing authorization header'); <-- these errors return the error message outlined below  
    }

    const supabaseClient = createClient(
      Deno.env.get('SUPABASE_URL') ?? '',
      Deno.env.get('SUPABASE_ANON_KEY') ?? '',
    );

    const token = authHeader.replace('Bearer ', '');
    const { data: { user }, error: userError } = await supabaseClient.auth.getUser(token);
    if (userError || !user) {
      throw new Error('Invalid user token');  <-- these errors return the Swift error message outlined below 
    }
[...] 
// Streaming code from LLM which works fine, including streamed errors.
} catch (error) {
    console.error('Error:', error);
    
    const status = error instanceof Error ? (
      error.message === 'Missing authorization header' || error.message === 'Invalid user token' ? 401 :
      error.message === 'Error fetching user profile' ? 403 :
      400
    ) : 500;

    return new Response(
      JSON.stringify({ 
        error: error instanceof Error ? error.message : 'Internal server error'
      }),
      {
        status,
        headers: { ...corsHeaders, 'Content-Type': 'application/json' }
      }
    );
  };

So the non-streaming errors show up as Unknown Error: Edge Function returned a non-2xx status code: 400 accompanied with API MISUSE: NSURLSession delegate Functions.StreamResponseDelegate: <Functions.StreamResponseDelegate: 0x600000035210> (0x600000035210) API MISUSE: dataTask:didReceiveResponse:completionHandler: completion handler not called Edge Function returned a non-2xx status code: 400 httpError(code: 400, data: 0 bytes)

cyrilzakka avatar Feb 24 '25 17:02 cyrilzakka