Line-item tags are mapped to balance-sheet total concepts, so a standardized statement returns several rows claiming to be the total. Affects standard_concept on any statement dataframe.
Version 5.43.0.
Repro
from edgar import Company
df = Company('CFG').get_financials().balance_sheet().to_dataframe()
df[df['standard_concept'] == 'Assets'][['concept', 'label', '2025-12-31']]
Citizens Financial Group, FY2025 — three rows:
| concept |
label |
2025-12-31 |
us-gaap_DebtSecuritiesHeldToMaturityExcludingAccruedInterestAfterAllowanceForCreditLoss |
Debt securities held to maturity |
7,933,000,000 |
us-gaap_BankOwnedLifeInsurance |
Bank-owned life insurance |
3,441,000,000 |
us-gaap_Assets |
TOTAL ASSETS |
226,351,000,000 |
Selecting on the standardized concept and taking the first row reports total assets as $7.9B instead of $226.4B.
No network needed:
from edgar.xbrl.standardization.core import MappingStore
MappingStore().get_standard_concept('us-gaap_BankOwnedLifeInsurance') # 'Total Assets'
MappingStore().get_standard_concept('ifrs-full_IntangibleAssetsAndGoodwill') # 'Total Non-Current Assets'
edgar/xbrl/standardization/reverse_index.py. 53 index entries sit in section: 'Totals' with is_total: True. Most are line items:
Total Assets Assets, AssetsNet, ifrs:Assets
+ AccruedInvestmentIncomeReceivable, BankOwnedLifeInsurance,
CashCashEquivalentsAndFederalFundsSold, FederalFundsSold,
FederalHomeLoanBankStock, InvestmentOwnedAtFairValue,
DebtSecuritiesHeldToMaturityExcludingAccruedInterest...
Total Liabilities Liabilities, ifrs:Liabilities
+ AdvancesFromFederalHomeLoanBanks, DueToRelatedPartiesCurrentAndNoncurrent,
ManagementFeePayable, OtherBorrowings, SecuredDebt,
SecuritiesSoldUnderAgreementsToRepurchase, SubordinatedDebt,
UnearnedPremiums, WarrantLiability,
SharesSubjectToMandatoryRedemptionSettlementTermsFairValueOfShares
Total Current Liabilities LiabilitiesCurrent, CurrentLiabilities
+ CurrentBorrowingsAndCurrentPortionOfNoncurrentBorrowings,
CurrentDerivativeFinancialLiabilities, CurrentPortionOfLongtermBorrowings,
CurrentProvisions, CurrentTaxLiabilitiesCurrent,
LiabilitiesIncludedInDisposalGroupsClassifiedAsHeldForSale,
OtherCurrentFinancialLiabilities, TemporaryEquityLiquidationPreference,
TradeAndOtherCurrentPayablesToRelatedParties
Total Current Assets AssetsCurrent, CurrentAssets
+ CurrentDerivativeFinancialAssets, CurrentPrepaymentsAndOtherCurrentAssets,
CurrentTaxAssetsCurrent, CurrentTradeReceivables, OtherCurrentReceivables,
CurrentAssetsOtherThanAssetsOrDisposalGroups...
Total Non-Current Assets AssetsNoncurrent, NoncurrentAssets, ifrs:NoncurrentAssets
+ IntangibleAssetsAndGoodwill, NoncurrentDerivativeFinancialAssets
The concentration is in bank and insurer line items (federal funds sold, FHLB stock, BOLI, unearned premiums, subordinated debt), which is why it doesn't show on a typical industrial filer. us-gaap_Goodwill maps correctly to Goodwill; the mis-mapped set is specific.
Separately, _normalize_tag (reverse_index.py:188) strips ifrs-full_ / ifrs-full: before lookup, so IFRS tags resolve against the GAAP index by bare name. On VEON's 20-F, ifrs-full_IntangibleAssetsAndGoodwill and ifrs-full_CurrentProvisions are labeled Total Non-Current Assets and Total Current Liabilities. VEON has 24 of 111 rows standardized, Klarna 16 of 81, so IFRS coverage is thin to begin with, the wrong mappings are the part that's actively misleading rather than just missing.
Random sample of 60 tickers from get_cik_tickers(), checking Assets == Liabilities + Equity per rendered period. The identity holds everywhere (0 mismatches over 98 periods, plus 49 large caps) because it reads raw concepts, the defect is only in the standardization layer.
Is gaap_taxonomy_mapping.csv the right place to fix this, or the index generation? The section: 'Totals' bucket looks like it's doing double duty, "this tag belongs to the totals region of the balance sheet" vs "this tag is the total", and is_total: True on a component is what makes it selectable as one. If the intended fix is in the source CSV I can't regenerate the index from the repo, since data/xbrl-mappings/ isn't checked in.
Happy to send a PR once you've said which layer it belongs in. A cheap guard in the meantime would be refusing is_total: True for a tag whose standard_tags is a *Total concept it isn't the canonical tag for, but that's a patch on the output.
Line-item tags are mapped to balance-sheet total concepts, so a standardized statement returns several rows claiming to be the total. Affects
standard_concepton any statement dataframe.Version 5.43.0.
Repro
Citizens Financial Group, FY2025 — three rows:
us-gaap_DebtSecuritiesHeldToMaturityExcludingAccruedInterestAfterAllowanceForCreditLossus-gaap_BankOwnedLifeInsuranceus-gaap_AssetsSelecting on the standardized concept and taking the first row reports total assets as $7.9B instead of $226.4B.
No network needed:
edgar/xbrl/standardization/reverse_index.py. 53 index entries sit insection: 'Totals'withis_total: True. Most are line items:The concentration is in bank and insurer line items (federal funds sold, FHLB stock, BOLI, unearned premiums, subordinated debt), which is why it doesn't show on a typical industrial filer.
us-gaap_Goodwillmaps correctly toGoodwill; the mis-mapped set is specific.Separately,
_normalize_tag(reverse_index.py:188) stripsifrs-full_/ifrs-full:before lookup, so IFRS tags resolve against the GAAP index by bare name. On VEON's 20-F,ifrs-full_IntangibleAssetsAndGoodwillandifrs-full_CurrentProvisionsare labeled Total Non-Current Assets and Total Current Liabilities. VEON has 24 of 111 rows standardized, Klarna 16 of 81, so IFRS coverage is thin to begin with, the wrong mappings are the part that's actively misleading rather than just missing.Random sample of 60 tickers from
get_cik_tickers(), checkingAssets == Liabilities + Equityper rendered period. The identity holds everywhere (0 mismatches over 98 periods, plus 49 large caps) because it reads raw concepts, the defect is only in the standardization layer.Is
gaap_taxonomy_mapping.csvthe right place to fix this, or the index generation? Thesection: 'Totals'bucket looks like it's doing double duty, "this tag belongs to the totals region of the balance sheet" vs "this tag is the total", andis_total: Trueon a component is what makes it selectable as one. If the intended fix is in the source CSV I can't regenerate the index from the repo, sincedata/xbrl-mappings/isn't checked in.Happy to send a PR once you've said which layer it belongs in. A cheap guard in the meantime would be refusing
is_total: Truefor a tag whosestandard_tagsis a*Totalconcept it isn't the canonical tag for, but that's a patch on the output.