fix: tolerate missing created_at/updated_at in LinkedAccount responses#148
Merged
Conversation
list_linked_accounts (GET /accounts) fails to deserialize on every call for some providers. The live response omits created_at/updated_at (e.g. linkedin_lms accounts), but the spec marks both required + non-nullable. Crystalline's strict from_dict raises KeyError on the missing key while building each nested LinkedAccount. Because the /accounts 200 response is a oneOf whose branches both wrap LinkedAccount, both branches fail and the Union returns nil (0.41.0) / raised TypeError (0.40.1) — the entire page is lost over two absent timestamps on one record. Make created_at/updated_at nullable and drop them from LinkedAccount's required list so the generated model deserializes accounts that lack them. Verified by regenerating locally (speakeasy 1.638.0, lint 0 errors, SDK generated successfully) and deserializing: - the exact payload from the bug report (timestamps absent) -> ok - a full payload with timestamps present -> ok, timestamps parsed - the bare-array oneOf branch -> ok Stopgap in the Ruby overlay; the real fix belongs in the OAS producer (make the fields nullable there, or always return them) to cover all SDKs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR updates the Speakeasy Ruby overlay to align the generated LinkedAccount model with observed /accounts API responses that sometimes omit created_at and updated_at, preventing deserialization failures when those timestamps are missing.
Changes:
- Marks
LinkedAccount.created_atandLinkedAccount.updated_atasnullable. - Removes
created_at/updated_atfromLinkedAccount.requiredand redefines the remaining required fields to keep the model constructible when timestamps are absent.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
jerann
approved these changes
Jul 21, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
accounts.list_linked_accounts(GET/accounts) fails to deserialize on every call for some providers. Reported against 0.40.1; still broken on 0.41.0 (fails differently — see below).Root cause is a spec-vs-reality mismatch on the nested
LinkedAccount:created_atandupdated_atas required + non-nullable.linkedin_lmsexample has neither).Crystalline's strict
from_dictraisesKeyError: key created_at not found in hashwhile building each nestedLinkedAccount. The/accounts200 response is aoneOfwhose branches both wrapLinkedAccount, so both fail and the whole page is lost over two absent timestamps on one record:Array<LinkedAccount>Union<LinkedAccountsPaginated, Array<LinkedAccount>>TypeErrorraisednilsilentlyEvidence the report's example is a real capture, not trimmed: it includes a
metadatafield that isn't in the OpenAPI schema at all.Fix
Overlay actions that make
created_at/updated_atnullableand drop them fromLinkedAccount.required, so the generated model deserializes accounts that lack them. (Both changes are needed: nullable alone leaves them keyword-required in the constructor →ArgumentError.)Verification
Regenerated locally (speakeasy 1.638.0, lint 0 errors, SDK generated successfully) and deserialized:
LinkedAccountsPaginated,data.size=1, timestampsnil✓oneOfbranch →Array<LinkedAccount>✓Follow-up (not in this PR)
Stopgap in the Ruby overlay. The real fix belongs in the OAS producer (
unified-cloud-api): either always returncreated_at/updated_at, or mark them nullable there — that covers the TS and PHP SDKs too, which have the same latent break.🤖 Generated with Claude Code