Firestore decode fails for an optional @ServerTimestamp field
Description
Decoding a Firestore document into a Codable model with an optional field marked @ServerTimestamp (e.g., var myTimestamp: Timestamp?) fails if the field is absent in the document. This is commonly needed let's say we're adding a new server write timestamp to an existing data model.
Reproducing the issue
struct TestModel: Codable {
@ServerTimestamp var optionalServerTs: Date?
var regularOptional: String?
var name: String
}
let docRef = db.collection("tests").document("missingOptionalTsDoc")
docRef.getDocument(as: TestModel.self) { result in
// Decoding fails here if 'optionalServerTs' is missing
// but 'regularOptional' (if missing) would correctly be nil.
}
Firebase SDK Version
11.12.0
Xcode Version
16.4
Installation Method
Swift Package Manager
Firebase Product(s)
Firestore
Targeted Platforms
iOS
Relevant Log Output
keyNotFound(CodingKeys(stringValue: "lastServerWriteTimestamp", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"lastServerWriteTimestamp\", intValue: nil) (\"lastServerWriteTimestamp\").", underlyingError: nil))
If using Swift Package Manager, the project's Package.resolved
No response
If using CocoaPods, the project's Podfile.lock
No response
I couldn't figure out how to label this issue, so I've labeled it for a human to triage. Hang tight.
Hi @fanwgwg, thank you for raising this issue. While I am looking into this, could you please try:
- change the
DatetoTimestamp: https://github.com/firebase/firebase-ios-sdk/blob/4f6c342424df416d78dfc12d08c97769fd4e1152/Firestore/Swift/Source/Codable/ServerTimestamp.swift#L64 - give it a default
nilvalue
Hey @fanwgwg. We need more information to resolve this issue but there hasn't been an update in 5 weekdays. I'm marking the issue as stale and if there are no new updates in the next 5 days I will close it automatically.
If you have more information that will help us get to the bottom of this, just add a comment!
@milaGGL Yes the same problem exists with Timestamp
HI @fanwgwg
could you please try if this approach can solve your problem?
let container = try decoder.singleValueContainer()
if container.decodeNil() {
value = nil
} else {
do {
value = try Value.wrap(container.decode(Timestamp.self))
} catch SPECIFIC_ERR {
value = nil
}
}
Hey @fanwgwg. We need more information to resolve this issue but there hasn't been an update in 5 weekdays. I'm marking the issue as stale and if there are no new updates in the next 5 days I will close it automatically.
If you have more information that will help us get to the bottom of this, just add a comment!
Since there haven't been any recent updates here, I am going to close this issue.
@fanwgwg if you're still experiencing this problem and want to continue the discussion just leave a comment here and we are happy to re-open this.
Reopened due to a new comment from @fanwgwg in #15293 . Copying that comment below:
Why a fix is still needed Unexpected Behavior: The current implementation breaks standard Swift Codable convention. Developers expect an optional property (var myDate: Date?) to become nil if its key is missing, but @ServerTimestamp instead throws a keyNotFound error. Wasted Developer Time: This forces developers to debug a common scenario (like adding a new timestamp field), find the workaround, and apply boilerplate code. Defeats the Purpose: Property wrappers like @ServerTimestamp exist to reduce boilerplate, but this issue forces developers to add more. The Solution The @ServerTimestamp decoder should gracefully handle a missing key for optional types by decoding the property to nil.
Fixing this in the SDK would make the API more intuitive, align it with standard Swift behavior, and save developers from unnecessary friction. Thank you.
The team reviewed this today. It does seem like something that should be fixed. But I need to follow up with @cherylEnkidu to determine if there was something previously blocking that fix.
Hey @fanwgwg. We need more information to resolve this issue but there hasn't been an update in 5 weekdays. I'm marking the issue as stale and if there are no new updates in the next 5 days I will close it automatically.
If you have more information that will help us get to the bottom of this, just add a comment!
Keeping this open. The team is investigating a fix.