Repository navigation
fix(sdk): wrap member decode errors with field context - #402
Merged
Merged
Conversation
Replace bare error returns in the congressional net worth JSON unmarshaling with calls to `memberDecodeError`, attaching the type name, field name, and raw value to each failure. This produces clearer, actionable error messages when decoding `CongressionalNetWorthRange` and `CongressionalMemberNetWorth` fields fails.
benbenbang
enabled auto-merge (squash)
October 1, 2026 03:46
ptah-bw-technical-app Bot
added a commit
that referenced
this pull request
Oct 2, 2026
## [1.2.0](1.1.0...1.2.0) (2026-10-02) ### ⚠ BREAKING CHANGES * **company:** CompanyProfile.isin, country, change and change_percentage are now optional in Rust, Python and Go, affecting both company.profile and bulk company_profiles. * **bulk:** every numeric member of BulkCashFlowStatement, BulkCashFlowStatementGrowth and BulkEodBar is now optional in Rust, Python and Go. * **bulk:** every numeric member of BulkBalanceSheetStatement and BulkBalanceSheetStatementGrowth is now optional in Rust, Python and Go. * **bulk:** every numeric member of BulkIncomeStatement and BulkIncomeStatementGrowth is now optional in Rust, Python and Go. * **bulk:** every numeric member of BulkKeyMetricsTtm, BulkFinancialRatiosTtm and BulkEarningsSurprise is now optional in Rust, Python and Go. * **bulk:** discounted_cash_flow_score, return_on_equity_score, return_on_assets_score, debt_to_equity_score, price_to_earnings_score, price_to_book_score, dcf, stock_price, reported_currency, altman_z_score, piotroski_score, working_capital, total_assets, retained_earnings, ebit, market_cap, total_liabilities, revenue, last_month_count, last_month_avg_price_target, last_quarter_count, last_quarter_avg_price_target, last_year_count, last_year_avg_price_target, all_time_count, all_time_avg_price_target, shares_number, asset, weight_percentage, isin, market_value, strong_buy, buy, hold, sell and strong_sell are now Option<NumericString> (asset Option<Ticker>, isin Option<Isin>, reported_currency Option<CurrencyCode>) in Rust, Optional[str] in Python and *string in Go. * **bulk:** the income-statement-bulk, income-statement-growth-bulk, balance-sheet-statement-bulk, balance-sheet-statement-growth-bulk, cash-flow-statement-bulk, cash-flow-statement-growth-bulk, and eod-bulk methods now require a text/csv response. * **bulk:** the four bulk methods KeyMetricsTTM, FinancialRatiosTTM, StockPeers, and EarningsSurprises now require a text/csv response and no longer decode JSON. * **bulk:** the seven snapshot bulk methods now require a text/csv response; BulkEtfHolding.last_updated_raw is renamed to last_updated and typed as Date in Rust, Python and Go. * **responses:** CongressionalMemberNetWorth and CongressionalMemberNetWorthAggregate no longer derive Eq (their f64 amounts); compare fields instead. * **responses:** CongressionalMemberNetWorth.value and the CongressionalMemberNetWorthAggregate amounts changed from i64 to f64 (MarketValue). CongressionalMemberNetWorth.category, name, owner and value, CongressionalNetWorthRange.max, CongressionalDebtDetails.date_incurred and CongressionalMemberNetWorthAggregate.real_estate, stock, real_estate_liabilities, business_and_self_employment, ownership_interest, options, revolving_and_credit_lines, asset_backed_securities and business_liabilities are now optional (Option / pointer / Optional); handle None. * **funds:** FundDisclosureSearchResult.entity_org_type is now optional (Option<NumericString> / *string / Optional[str]); the provider's "NULL" text and null decode as None, so handle None. * **libfmp:** a 200 response whose body is an FMP error message (a short plain-text line such as Invalid name, or a JSON object whose only member is "Error Message") now fails with ErrorCategory::Status and status_code Some(200) instead of ErrorCategory::Decode; Python raises FmpStatusError instead of FmpDecodeError. Match on the Status category to handle it. * **sdk/go:** a 200 response whose body is an FMP error message (a short plain-text line such as Invalid name, or a JSON object whose only member is "Error Message") now fails with CategoryStatus and Status 200 instead of CategoryDecode. Match on CategoryStatus to handle it. * **indexes:** IndexConstituent.founded is now String (Rust) / string (Go) / str (Python) holding the founding year(s) verbatim, e.g. "1994" or "1902/1985"; it was a Date. Compare or parse the string instead of a date. * **calendar:** IpoProspectus.ipo_date is now DateOrYear in Rust (match Date or Year, or use as_date/as_year), datetime.date | int in Python (a bare year is an int), and fmp.DateOrYear in Go (use .Date() / .Year()). * **responses:** CrowdfundingOffering, RegulationDOffering, SecCompanyProfile and SecCompanySearchResult members FMP can omit are now optional (Option / pointer / Optional); handle None. * **crypto:** CryptocurrencyListing members FMP can omit are now optional (Option / pointer / Optional); handle None. * **responses:** NewsArticle, ExchangeHoliday, EsgDisclosure, EsgRating and CongressionalMemberProfile members FMP can omit are now optional (Option / pointer / Optional); handle None. * **statements:** IncomeStatement, KeyMetrics, KeyMetricsTtm, FinancialScore, AsReportedFinancialStatement and FinancialEstimate members FMP can omit are now optional (Option / pointer / Optional); handle None. * **directory:** AvailableExchange, FinancialStatementSymbol and HistoricalIndexConstituent members FMP can omit are now optional, and "" on their typed codes decodes as None (Option / pointer / Optional); handle None. * **insider-trading:** InsiderTrade, BeneficialOwnershipAcquisition, InstitutionalHolding and HolderIndustryBreakdown members FMP can omit are now optional (Option / pointer / Optional); handle None. * **funds:** EtfFundHolding, FundDisclosure and FundDisclosureSearchResult members FMP can omit are now optional (Option / pointer / Optional); handle None. * **calendar:** DividendEvent, EarningsEvent, IpoCalendarEvent, IpoProspectus and StockSplitEvent members FMP can omit are now optional (Option / pointer / Optional); handle None. * **search:** ExchangeVariant and CompanyScreenerResult members FMP can omit are now optional (Option / pointer / Optional); handle None. * **statements:** 57 BalanceSheetStatement and CashFlowStatement amounts are now optional (Option / pointer / Optional); callers must handle None. * **economics:** TreasuryRate tenors, EconomicIndicatorObservation.value and six EconomicCalendarEvent members are now optional (Option / pointer / Optional); handle None. * **quote:** QuoteShort price, change and volume and AftermarketTrade.tradeSize are now optional (Option / pointer / Optional); callers must handle None. * **company:** CompanyProfile, CompanyExecutive, CompanyMarketCapitalization, CompanyNote, CompanyShareFloat, ShareFloat, ExecutiveCompensation and MergerAcquisition members FMP can omit are now optional (Option / pointer / Optional); handle None. * **statements:** financial_reports_json now returns a single FinancialReportJson instead of a list; drop the [0] / iteration. * **responses:** cover null aggregate fields decoding as None ([351281b](351281b)) ### 🎁 Features * **calendar:** make omittable calendar members optional ([fefb037](fefb037)) * **codecs:** add DateOrYear for date-or-year wire fields ([0d2bac5](0d2bac5)) * **codecs:** add empty_or_null deserializer for nullable typed codes ([98a10f9](98a10f9)), closes [#368](#368) * **company:** make provider-omittable company members optional ([370d0b4](370d0b4)) * **crates:** support single-model endpoints in generators ([3673318](3673318)) * **crypto:** make omittable CryptocurrencyListing members optional ([f69fdef](f69fdef)) * **directory:** make omittable directory and index members optional ([eefaaf8](eefaaf8)) * **economics:** make treasury tenors and calendar figures optional ([b3a7969](b3a7969)), closes [#368](#368) [#368](#368) * **fmp-py-gen:** use ClientHandle for namespace clients ([8b6baf1](8b6baf1)) * **fmp-py:** add close and context manager support to FmpClient ([43e3944](43e3944)) * **funds:** make omittable fund members optional ([64eab5b](64eab5b)) * **gen-go:** add empty_or_null string codec for Go models ([0bb05b0](0bb05b0)) * **go-sdk:** add CloseIdleConnections to release the owned pool ([85651e9](85651e9)), closes [#371](#371) * **insider-trading:** make FMP-omittable members optional ([9c96061](9c96061)) * **quote:** make QuoteShort and AftermarketTrade fields optional ([716455c](716455c)) * **responses:** make omittable fundraising and sec filings members optional ([4850095](4850095)) * **responses:** make omittable news, market hours, esg and congressional members optional ([9ce3a15](9ce3a15)) * **sdk/go:** add DateOrYear temporal type ([d9de466](d9de466)) * **search:** make omittable ExchangeVariant and screener members optional ([b79c55b](b79c55b)) * **statements:** make FMP-omittable statement members optional ([d4fde87](d4fde87)) * **statements:** make pre-IPO stub-quarter amounts optional ([683b04e](683b04e)) ### ♨️ CI, Workflows & Configs * **env:** add .envrc for direnv configuration ([#373](#373)) ([78da933](78da933)) ### 🪲 Bug Fixes * **bulk:** decode final seven bulk routes as text/csv ([78aa5f9](78aa5f9)), closes [#376](#376) * **bulk:** decode metric bulk routes as CSV ([21b5c9b](21b5c9b)), closes [#376](#376) * **bulk:** decode snapshot bulk routes as text/csv ([d30ffc2](d30ffc2)) * **bulk:** make balance-sheet numeric members optional ([5665926](5665926)) * **bulk:** make bulk income numeric members optional ([73e45f6](73e45f6)) * **bulk:** make empty numeric snapshot cells optional per ADR 0035 ([473402f](473402f)), closes [#376](#376) * **bulk:** make numeric cash-flow and EOD members optional ([514567e](514567e)) * **bulk:** make numeric metric members optional for empty cells ([22ca885](22ca885)) * **calendar:** decode a bare year ipoDate as a year, not a date ([ac0c07b](ac0c07b)), closes [#379](#379) [#379](#379) * **company:** make profile isin, country and change optional ([23fb211](23fb211)), closes [#376](#376) * **csv:** strip leading UTF-8 BOM before the Go CSV header ([7c8cd51](7c8cd51)) * **fmp-py-gen:** resolve CSV contract in wire resolver and gen_go ([77c3d08](77c3d08)), closes [#376](#376) * **fmp-py:** map provider error bodies to FmpStatusError ([b206669](b206669)) * **fmp-py:** return None from client __exit__ to propagate exceptions ([9e18f76](9e18f76)) * **funds:** decode "NULL" entityOrgType as absent ([2e07672](2e07672)), closes [#380](#380) * **indexes:** keep IndexConstituent.founded verbatim as a string ([ac87c1a](ac87c1a)), closes [#378](#378) * **libfmp:** add CSV response contract and row decoder ([afee377](afee377)), closes [#376](#376) * **libfmp:** raise CSV bulk body limit to 256 MiB default ([a25b8db](a25b8db)), closes [#376](#376) * **libfmp:** require every CSV row member to be a header column ([780c562](780c562)), closes [#376](#376) * **libfmp:** treat FMP error messages on HTTP 200 as status errors ([f570df9](f570df9)) * **responses:** decode congressional net worth as fractional and optional ([95c0685](95c0685)) * **sdk/go/artifact:** route member unmarshal errors through memberDecodeError ([5d00bf4](5d00bf4)) * **sdk/go:** handle text/csv bulk responses with larger body limit ([1b4a66b](1b4a66b)), closes [#376](#376) * **sdk/go:** keep member path on nullable and codec decode failures ([c163be0](c163be0)) * **sdk/go:** require every model member to be a CSV header column ([9f0e19e](9f0e19e)), closes [#376](#376) * **sdk/go:** treat FMP error messages on HTTP 200 as status errors ([27c4ed9](27c4ed9)) * **sdk:** wrap member decode errors with field context ([#402](#402)) ([2356304](2356304)) * **statements:** return one financial report json object not a list ([3e7eb61](3e7eb61))
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.
Replace bare error returns in the congressional net worth JSON
unmarshaling with calls to
memberDecodeError, attaching the type name,field name, and raw value to each failure. This produces clearer,
actionable error messages when decoding
CongressionalNetWorthRangeandCongressionalMemberNetWorthfields fails.