Could not convert database value NULL to String

Hi, I'm getting this error when doing a simple fetch. Xcode 10.2.1, Swift 5, GRDB 4.0.1.

The bannerPath is an Optional String:

I'm not sure why this would be the case. Any suggestions on this? Presumably the NULL type would be converted to nil.

Here is the fetching code:

    public func fetchPlaylists(for channelUuid: String) -> Single<[Playlist]> {
        return Single.create { [unowned self] single in
            do {
                var fetched: [Playlist] = []
                try self.dbPool.read { db in
                    fetched = try Playlist.filter(Column("channelUuid") == channelUuid).fetchAll(db)
                }
                single(.success(fetched))
            } catch {
                DDLogDebug("error: \(error)")
                single(.error(error))
            }
            return Disposables.create {}
        }
    }

This is the error location in the log:

file /Users/michael/src/kjvrvg-ios/Pods/GRDB.swift/GRDB/Core/DatabaseValueConversion.swift, line 146

NOTE: it reports it as line 146 but the compiler throws the fatalError() exception at line 132, slightly above. The function signature where the crash is:

/// The canonical conversion fatal error
///
/// - parameter dbValue: nil means "missing column", for consistency with (row["missing"] as DatabaseValue? == nil)
func fatalConversionError<T>(to: T.Type, from dbValue: DatabaseValue?, conversionContext: ValueConversionContext?, file: StaticString = #file, line: UInt = #line) -> Never {

Regards,
Michael

Hello @mazz,

When you provide custom decoding code for the standard Decodable protocol, you should use the decodeIfPresent method for optional values that may be missing (NULL in SQLite, null in JSON, etc.)

This will remove your crash.

Now, since your Playlist type only contains Decodable properties, the compiler can generate everything for you. This may be your best option. See the " Encode and Decode Automatically" chapter in the Encoding and Decoding Custom Types documentation.

With GRDB, this generally gives:

public struct Playlist: Codable {
    // Only properties
    var uuid: String
    ...
}

extension Playlist: FetchableRecord, PersistableRecord { }

Finally, since your Playlist has a string primary key, remove your implementation of didInsert(with:for:), and pick the PersistableRecord protocol. Generally, only define the didInsert method when your record type has an auto-incremented numeric primary key, as documented.

1 Like

By the way, @mazz, please open Github issues for this kind of question, in the future. Why? Because other users, who face the same issue, are more likely to search for it in issues rather than in the forums. You'll always be welcome wherever you ask for support, but it's a little bit too close to a private lesson, here.

Ok thanks for the detailed response and in the future I will definitely make a github issue instead. Have a great day!

1 Like