Search code examples
swiftpostgresqlserverfluentvapor

Vapor server: Fatal error: Cannot access field before it is initialized or fetched: address


I have a vapor (4) server and recently added a function to query the database for a resident using an email address:

func getResidentByEmail(req: Request) throws -> EventLoopFuture<Resident> {
        let token = try req.auth.require(Token.self)
        let email = req.parameters.get("email") ?? ""
            return Resident.query(on: req.db)
                .filter(\.$email == email)
                .first()
                .map { resident in
                    
                    guard let resident else { return Resident()  }
                    
                    return resident
                }
    }

Initially this function worked: I was able to return a resident with an email address. Now my server crashes with this error:

FluentKit/Field.swift:23: Fatal error: Cannot access field before it is initialized or fetched: address

I don't understand where I'm accessing the address field before it's initialized. If I restart the server this might say phoneNumber instead of address or some other field, but the rest of the error stays the same.

Here's my Resident model:

final class Resident: Model, Content {
    init() {
    }

    static let schema: String = "residents"
    
    @ID(key: .id)
    var id: UUID?
    
    @Field(key: "firstName")
    var firstName: String
    
    @Field(key: "middleName")
    var middleName: String
    
    @Field(key: "lastName")
    var lastName: String
    
    @Field(key: "phoneNumber")
    var phoneNumber: String
    
    @Field(key: "email")
    var email: String
    
    @Field(key: "dob")
    var dob: String
    
    @Field(key: "address")
    var address: String
    
    @Field(key: "rentAmount")
    var rentAmount: Double
    
    @Field(key: "pastDueRentOwed")
    var pastDueRentOwed: Double
    
    @Field(key: "isPastDue")
    var isPastDue: Bool
    
    @Field(key: "isRetiredClient")
    var isRetiredClient: Bool
    
    @Field(key: "monthlyReminderScheduled")
    var monthlyReminderScheduled: Bool
    
    @Field(key: "house")
    var house: String
    
    @Field(key: "roomNumber")
    var roomNumber: Int
    
    @Field(key: "bedNumber")
    var bedNumber: Int
    
    @Field(key: "housePin")
    var housePin: Int
    
    @Field(key: "moveInDate")
    var moveInDate: String



Solution

  • Instead of returning a new Resident instance with an empty initializer when no resident is found, handle the absence of a resident more appropriately. Try this

    func getResidentByEmail(req: Request) throws -> EventLoopFuture<Resident> {
        let token = try req.auth.require(Token.self)
        let email = req.parameters.get("email") ?? ""
        return Resident.query(on: req.db)
            .filter(\.$email == email)
            .first()
            .unwrap(or: Abort(.notFound, reason: "Resident with email \(email) not found"))
    }