SwiftUI "Failed to look up SRV record"

I am trying to connect to a serverless Mongodb instance in Atlas. The only connection string provided is the srv version. I have setup the code following the examples in the docs for the driver. I have tested in a command line app and in a SwiftUI app using both async and sync methods.

When calling collection.insertOne(doc), I receive the following error for both async and sync methods ONLY on SwiftUI tests. The same code works fine in a command line app in the same environment.

ConnectionError(message: “Failed to look up SRV record "_mongodb._tcp.main.ua0ol.mongodb.net": A temporary error occurred on an authoritative name server. Try again later.”, errorLabels: nil)

Again… this works fine with a command line test app using the same connection code so I know this isn’t a network or dns issue. It seems to be something about how the driver works in a SwiftUI environment.

I am using the main branch of the driver repo in the swift package manager UI. No version is specified so “main” is latest, as I understand, though I’ve also tried specifying 1.3.1+.

Thanks for any help here.

Code for both tests is as follows:

MongoTestUIApp.swift

import SwiftUI

@main
struct MongoTestUIApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

ContentView.swift

import SwiftUI
import MongoSwiftSync
import MongoSwift
import NIOPosix

struct ContentView: View {
    
    @State var count:UInt64 = 28
    
    var body: some View {
        VStack {
            Text("Hello, world!")
            Button("Run") {
                runSyncTest()
//                Task {
//                    await runAsyncTest()
//                }
            }
        }
        .padding()
    }
    
    func runAsyncTest() async {
        do {
            let elg = MultiThreadedEventLoopGroup(numberOfThreads: 4)
            let client = try MongoClient("mongodb+srv://username:password@main.ua0ol.mongodb.net/?retryWrites=true&w=majority", using: elg)
            defer {
                // clean up driver resources
                try? client.syncClose()
                cleanupMongoSwift()
                // shut down EventLoopGroup
                try? elg.syncShutdownGracefully()
            }
            
            let db = client.db("office")
            print("made db")
            let collection = try await db.collection("items")
            print("got collection")
            
            let item = Item(id:count, name:"Crate \(count)")
            count += 1
            
            let doc: BSONDocument = try BSONEncoder().encode(item) // entity.createDoc()
            let result = try await collection.insertOne(doc)
            print(result?.insertedID ?? "")
        } catch {
            print(error)
        }
    }
    
    func runSyncTest() {
        do {
            defer {
                // free driver resources
                cleanupMongoSwift()
            }
            
            let client = try MongoClient("mongodb+srv://username:password@main.ua0ol.mongodb.net/?retryWrites=true&w=majority")
            
            let db = client.db("office")
            let collection = db.collection("items")
            
            let item = Item(id:count, name:"Crate \(count)")
            count += 1
            
            let doc: BSONDocument = try BSONEncoder().encode(item)
            print("adding item")
            let result = try collection.insertOne(doc)
            print(result?.insertedID ?? "") // prints `.int64(100)`
        } catch {
            print(error)
        }
    }
}

struct Item: Encodable, Identifiable, Hashable {
    var id: UInt64?
    var name: String = ""
    var version: Int = 1
    var description: String?
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Command line app - main.swift

import Foundation
import MongoSwiftSync
import MongoSwift
import NIOPosix

let item = Item(id:8, name:"Crate 8")

syncTest()
//asyncTest()

func asyncTest() {
    Task {
        do {
            let elg = MultiThreadedEventLoopGroup(numberOfThreads: 4)
            let client = try MongoClient("mongodb+srv://username:password@main.ua0ol.mongodb.net/?retryWrites=true&w=majority", using: elg)
            defer {
                // clean up driver resources
                try? client.syncClose()
                cleanupMongoSwift()
                // shut down EventLoopGroup
                try? elg.syncShutdownGracefully()
            }
            
            let db = client.db("office")
            let collection = try await db.createCollection("items")
            
            let doc: BSONDocument = try BSONEncoder().encode(item) // entity.createDoc()
            print("adding item")
            let result = try await collection.insertOne(doc)
        } catch {
            print(error)
        }
    }
}

func syncTest() {
    do {
        defer {
            // free driver resources
            cleanupMongoSwift()
        }
        
        let client = try MongoClient("mongodb+srv://username:password@main.ua0ol.mongodb.net/?retryWrites=true&w=majority")
        
        let db = client.db("office")
        let collection = db.collection("items")
        
        let doc: BSONDocument = try BSONEncoder().encode(item)
        print("adding item")
        let result = try collection.insertOne(doc)
        print(result?.insertedID ?? "") // prints `.int64(100)`
    } catch {
        print(error)
    }
}


struct Item: Encodable, Identifiable, Hashable {
    var id: UInt64?
    var name: String = ""
    var version: Int = 1
    var description: String?
}
1 Like

Are the command line app and the SwiftUI app running in the same environment? This looks to me like a DNS failure trying to look up the SRV record; perhaps there’s a difference in the environments?

Yeah, same environment. That’s what makes it interesting and rules out any DNS or env related issue. It must be something about the SwiftUI framework. Maybe threading in the UI or some UI related configuration like privileges (brainstorming)… I’m not sure.

thanks, I see you opened a support case, your support engineer will follow up and I’ll keep an eye on it

In case anyone finds this in a search, the cause of this issue was the app sandbox. You must enable both outgoing AND incoming connections, even though your app may not ever accept incoming connections and the driver itself doesn’t need an incoming connection to do the dns lookup and connect to Mongo. The Mongo support team so far is not sure why incoming connections must be allowed for the driver to work. I don’t see any reason but that’s how it is today.

If anyone has any details on why incoming connections need to be configured on the sandbox to avoid this error, please share. There is a firewall between the app and Mongo that will not let any incoming connection through so no connection is actually initiated from outside the firewall or app, however allowing incoming connections on the sandbox is what makes this error go away.

The MongoDB Swift driver imbeds the MongoDB C driver to do its system functions, and the C driver in turn does a Linux system call to resolve the DNS name. This works everywhere except the App Sandbox with incoming connections disabled. Why, exactly, the App Sandbox requires incoming connections enabled for applications that use Linux syscalls to resolve DNS addresses, and whether Apple considers this a bug or working as designed, is a question for Apple App Sandbox support. I’d be very interested to hear that answer.

In any case, thanks for bringing this up on this forum and with MongoDB Support. It is an interesting use case and I learned some things while helping with it.

Thanks for the extra insight Spencer.

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.