Subclassing URLProtocol for testing URLSession calls problem / error when using async await

Hi all,

I am writing tests by subclassing URLProtocol to mock the responses. Same pattern as discussed in this article. I am using async await with URLSession (ie let (data, response) = try await request, delegate: nil) ) it does not work and I get an error (see below).

Any thoughts on how I can solve this error?

Many thanks.

Thread 4: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)

The full message:

Foundation`merged closure #1 (Swift.Optional<Foundation.Data>, Swift.Optional<__C.NSURLResponse>, Swift.Optional<Swift.Error>) -> () in closure #1 (Swift.CheckedContinuation<(Foundation.Data, __C.NSURLResponse), Swift.Error>) -> () in closure #2 () async throws -> (Foundation.Data, __C.NSURLResponse) in Foundation.URLRequest, delegate: Swift.Optional<__C.NSURLSessionTaskDelegate>) async throws -> (Foundation.Data, __C.NSURLResponse):
    0x7ff80d4cc520 <+0>:   pushq  %rbp
    0x7ff80d4cc521 <+1>:   movq   %rsp, %rbp
    0x7ff80d4cc524 <+4>:   pushq  %r13
    0x7ff80d4cc526 <+6>:   pushq  %rbx
    0x7ff80d4cc527 <+7>:   subq   $0x20, %rsp
    0x7ff80d4cc52b <+11>:  movq   %r8, %r13
    0x7ff80d4cc52e <+14>:  testq  %rcx, %rcx
    0x7ff80d4cc531 <+17>:  je     0x7ff80d4cc559            ; <+57>
    0x7ff80d4cc533 <+19>:  movq   %rcx, -0x28(%rbp)
    0x7ff80d4cc537 <+23>:  movq   %rcx, %rdi
    0x7ff80d4cc53a <+26>:  callq  0x7ff80d8a566e            ; symbol stub for: swift_errorRetain
    0x7ff80d4cc53f <+31>:  leaq   0x407d5352(%rip), %rdi    ; demangling cache variable for type metadata for Swift.CheckedContinuation<(Foundation.Data, __C.NSURLResponse), Swift.Error>
    0x7ff80d4cc546 <+38>:  callq  0x7ff80d329890            ; __swift_instantiateConcreteTypeFromMangledName
    0x7ff80d4cc54b <+43>:  leaq   -0x28(%rbp), %rdi
    0x7ff80d4cc54f <+47>:  movq   %rax, %rsi
    0x7ff80d4cc552 <+50>:  callq  0x7ff80d8a2b60            ; symbol stub for: Swift.CheckedContinuation.resume(throwing: __owned τ_0_1) -> ()
    0x7ff80d4cc557 <+55>:  jmp    0x7ff80d4cc5a1            ; <+129>
    0x7ff80d4cc559 <+57>:  movq   %rsi, %rax
    0x7ff80d4cc55c <+60>:  shrq   $0x38, %rax
    0x7ff80d4cc560 <+64>:  cmpl   $0xfe, %eax
    0x7ff80d4cc565 <+69>:  ja     0x7ff80d4cc5aa            ; <+138>
    0x7ff80d4cc567 <+71>:  movq   %rdx, %rbx
    0x7ff80d4cc56a <+74>:  testq  %rdx, %rdx
    0x7ff80d4cc56d <+77>:  je     0x7ff80d4cc5ac            ; <+140>
    0x7ff80d4cc56f <+79>:  movq   %rdi, -0x28(%rbp)
    0x7ff80d4cc573 <+83>:  movq   %rsi, -0x20(%rbp)
    0x7ff80d4cc577 <+87>:  movq   %rbx, -0x18(%rbp)
    0x7ff80d4cc57b <+91>:  callq  0x7ff80d42ed20            ; outlined copy of Swift.Optional<Foundation.Data>
    0x7ff80d4cc580 <+96>:  movq   %rbx, %rdi
    0x7ff80d4cc583 <+99>:  callq  *0x41e2fa5f(%rip)
    0x7ff80d4cc589 <+105>: leaq   0x407d5308(%rip), %rdi    ; demangling cache variable for type metadata for Swift.CheckedContinuation<(Foundation.Data, __C.NSURLResponse), Swift.Error>
    0x7ff80d4cc590 <+112>: callq  0x7ff80d329890            ; __swift_instantiateConcreteTypeFromMangledName
    0x7ff80d4cc595 <+117>: leaq   -0x28(%rbp), %rdi
    0x7ff80d4cc599 <+121>: movq   %rax, %rsi
    0x7ff80d4cc59c <+124>: callq  0x7ff80d8a2b66            ; symbol stub for: Swift.CheckedContinuation.resume(returning: __owned τ_0_0) -> ()
    0x7ff80d4cc5a1 <+129>: addq   $0x20, %rsp
    0x7ff80d4cc5a5 <+133>: popq   %rbx
    0x7ff80d4cc5a6 <+134>: popq   %r13
    0x7ff80d4cc5a8 <+136>: popq   %rbp
    0x7ff80d4cc5a9 <+137>: retq   
    0x7ff80d4cc5aa <+138>: ud2    
->  0x7ff80d4cc5ac <+140>: ud2    
    0x7ff80d4cc5ae <+142>: nop    

Note: someone else had asked about the same issue here on stackoverflow too for reference.

1 Like

The issue turned out to be:

In my mock URLProtocol where I had overridden the startLoading() method, I had forgotten to add:

client?.urlProtocol(self, didReceive: HTTPURLResponse(), cacheStoragePolicy: .allowed)

After I added this, the issue was resolved.