FEMA Declarations That Will Not Join to Counties: Statewide and Tribal Rows

On this page

Problem statement

Join FEMA's declaration rows to Census counties on state and county FIPS and 2,278 rows fall out. Most have county code 000: statewide declarations, which cover every county but name none, and declarations for tribal nations, which are not counties at all. The rest carry county codes that no longer exist or never matched the Census file. Dropped silently, they remove whole statewide fire and flood declarations from a map and erase tribal declarations entirely. This page finds each kind of unmatched row and shows how to keep them.

Quick answer

Split the rows before joining. Rows with designatedArea == "Statewide" should be expanded to every county of the state. Tribal rows (tribalRequest == 1, or a reservation or tribe name with code 000) belong to a tribal geography such as Census AIANNH areas. Remaining mismatches are mostly Connecticut's old counties and territories missing from the county file; join those with a matching vintage.

dds["GEOID"] = dds.fipsStateCode + dds.fipsCountyCode
ok = dds.GEOID.isin(counties.GEOID)
print(f"rows matching a 2023 Census county: {ok.mean():.1%}; not matching: {(~ok).sum():,}")
miss = dds[~ok]
print(miss.assign(kind=np.where(miss.fipsCountyCode == "000", "county code 000", "other code")).kind.value_counts().to_dict())
rows matching a 2023 Census county: 96.8%; not matching: 2,278
{'county code 000': 1612, 'other code': 666}

96.8% of rows match a 2023 Census county. Of the 2,278 that do not, 1,612 have county code 000 and 666 have some other code.

Horizontal bars of declaration rows that do not match a 2023 county: code 000 tribal 987, statewide 464, other 161, and other codes for Connecticut 244 and the territories. Horizontal bars of declaration rows that do not match a 2023 county: code 000 tribal 987, statewide 464, other 161, and other codes for Connecticut 244 and the territories.
Why 2,278 declaration rows fall out of a county join.

Statewide, tribal and changed codes

1. County code 000

z = dds[dds.fipsCountyCode == "000"]
kind = np.select([z.designatedArea.eq("Statewide"), z.tribalRequest.eq(1) | z.designatedArea.str.contains("Tribe|Reservation|Pueblo|Nation|Indian|Band|Rancheria", case=False)],
                 ["statewide", "tribal"], "other")
print(pd.Series(kind).value_counts().to_dict())
print(z[kind == "other"].designatedArea.value_counts().head(5).to_dict())
{'tribal': 987, 'statewide': 464, 'other': 161}
{'Tanana (ANV/ANVSA)': 12, 'Mohegan Trust Lands': 5, 'Pawnee (OTSA)': 4, 'Samish (TDSA)': 3, 'Tok (ANV/ANVSA)': 3}

Of the code-000 rows, 987 are tribal areas, 464 are statewide and 161 are other non-county areas, such as Alaska Native villages (Tanana, Tok), the Mohegan Trust Lands and Oklahoma tribal statistical areas (Pawnee).

2. Expand statewide rows

sw = dds[dds.designatedArea == "Statewide"]
exp = sw.merge(counties[["STATEFP", "GEOID"]].rename(columns={"GEOID": "GEOID_c"}), left_on="fipsStateCode", right_on="STATEFP")
print(f"{len(sw)} statewide rows become {len(exp):,} county rows; incident types: {sw.drop_duplicates('disasterNumber').incidentType.value_counts().head(4).to_dict()}")
464 statewide rows become 45,820 county rows; incident types: {'Fire': 266, 'Flood': 104, 'Hurricane': 37, 'Tornado': 15}

The 464 statewide rows expand to 45,820 county rows. Most are fire management declarations (266), followed by floods (104) and hurricanes (37). Dropping them removes these declarations from a county map entirely, and keeping them unexpanded leaves them unmapped.

Map of US states shaded by the number of declarations with a statewide row, darkest in Washington, Texas, Oklahoma and Florida. Map of US states shaded by the number of declarations with a statewide row, darkest in Washington, Texas, Oklahoma and Florida.
Statewide declarations by state: 464 rows that expand to 45,820 county rows.

3. Codes that changed

other = dds[~ok & (dds.fipsCountyCode != "000")]
print(other.state.value_counts().head(6).to_dict())
print(other[other.state == "CT"].designatedArea.value_counts().head(4).to_dict())
print(other[other.state == "AK"].designatedArea.value_counts().head(4).to_dict())
{'CT': 244, 'MP': 94, 'VI': 84, 'AS': 75, 'MH': 50, 'AK': 34}
{'New Haven (County)(in (P)MSA 1160,5480,8880)': 36, 'Fairfield (County)(in PMSA 1160,1930,5760,8040)': 33, 'Litchfield (County)(in (P)MSA 1170,1930,3280,8880)': 31, 'Hartford (County)(in PMSA 1170,3280,5440)': 30}
{'Kashunamiut Regional Educational Attendance Area': 6, 'Wade Hampton (Census Area)': 5, 'Valdez-Cordova (Census Area)': 5, 'Chugach Regional Educational Attendance Area': 5}

The other mismatches are Connecticut (244 rows), whose eight counties were replaced by planning regions in the Census Bureau's 2022 geography, and island territories absent from the 20m county file (the Northern Marianas, US Virgin Islands, American Samoa, the Marshall Islands). Some Connecticut rows still carry metropolitan-area notes in the area name, and Alaska's include renamed or split census areas (Wade Hampton, Valdez-Cordova) and regional education attendance areas.

Tribal declarations and a complete join

The data used on this page

FEMA's Disaster Declarations Summaries from OpenFEMA, saved on this site on 15 October 2026, and Census Bureau 2023 county and state boundaries.

from pathlib import Path

import geopandas as gpd
import numpy as np
import pandas as pd
import requests

Path("data").mkdir(exist_ok=True)
# OpenFEMA, queried on 15 October 2026 and saved on this site because both datasets are revised continually:
# DisasterDeclarationsSummaries v2 (every declaration since 1953, one row per designated area) and NfipClaims v3
# (flood insurance claims with a loss in 2017 or later, 29 fields). The queries are in data/README.txt; the live API is
# https://www.fema.gov/api/open/v2/DisasterDeclarationsSummaries and https://www.fema.gov/api/open/v3/NfipClaims
FILES = ["fema-disaster-declarations-2026-10-15.zip", "nfip-claims-2017-2026-2026-10-15.zip"]
for name in FILES:
    if not Path(f"data/{name}").exists():
        Path(f"data/{name}").write_bytes(requests.get(f"https://data.spatialworkflow.io/{name}", timeout=600).content)
dds = pd.read_csv("data/fema-disaster-declarations-2026-10-15.zip", dtype={"fipsStateCode": str, "fipsCountyCode": str, "placeCode": str},
                  parse_dates=["declarationDate", "incidentBeginDate", "incidentEndDate"])
for name in ["cb_2023_us_county_20m.zip", "cb_2023_us_state_20m.zip"]:
    if not Path(f"data/{name}").exists():
        Path(f"data/{name}").write_bytes(requests.get(f"https://www2.census.gov/geo/tiger/GENZ2023/shp/{name}", timeout=300).content)
counties = gpd.read_file("data/cb_2023_us_county_20m.zip").to_crs(5070)
states = gpd.read_file("data/cb_2023_us_state_20m.zip").to_crs(5070)
print(f"OpenFEMA: {len(dds):,} declaration rows for {dds.disasterNumber.nunique():,} declarations, "
      f"{dds.declarationDate.min():%Y}-{dds.declarationDate.max():%Y}")
OpenFEMA: 70,567 declaration rows for 5,281 declarations, 1953-2026

Example 1: tribal declarations

tr = dds[dds.tribalRequest == 1].drop_duplicates("disasterNumber")
print(f"declarations requested directly by tribal governments: {len(tr)}, first {tr.declarationDate.min():%Y}; by type {tr.declarationType.value_counts().to_dict()}")
print(tr.incidentType.value_counts().head(5).to_dict())
declarations requested directly by tribal governments: 127, first 2013; by type {'DR': 69, 'EM': 58}
{'Biological': 55, 'Severe Storm': 29, 'Flood': 15, 'Hurricane': 8, 'Winter Storm': 5}

Since 2013, tribal governments can request declarations directly from the President rather than through a state. 127 such declarations have been made, 69 major disasters and 58 emergencies, 55 of them for COVID-19. They need tribal boundaries, not counties, to be mapped at all.

Stacked bar chart of declarations requested directly by tribal governments from 2013 to 2026, a few a year apart from a large spike of emergencies in 2020. Stacked bar chart of declarations requested directly by tribal governments from 2013 to 2026, a few a year apart from a large spike of emergencies in 2020.
127 tribal declarations since 2013, 55 of them for COVID-19.

Example 2: a join that keeps everything

fixed = pd.concat([dds[ok].assign(join_geoid=dds.GEOID[ok]),
                   exp.assign(join_geoid=exp.GEOID_c).drop(columns=["STATEFP", "GEOID_c"])])
print(f"rows after expanding statewide declarations: {len(fixed):,}; distinct county-declarations: {fixed.drop_duplicates(['disasterNumber', 'join_geoid']).shape[0]:,}")
rows after expanding statewide declarations: 114,109; distinct county-declarations: 112,239

With matched rows plus the expanded statewide rows, the table has 114,109 rows and 112,239 distinct county designations. That is the table to map, with tribal and territory rows kept beside it rather than thrown away.

Why 000

FIPS county code 000 conventionally means "the whole state" or "no county", and FEMA uses it for any designated area that is not a single county: the entire state, a tribal nation that may span several counties and states, or a statistical area. The designated area's name, and for tribes tribalRequest, say which. A county join cannot place these rows, so they have to be handled before it, not discovered after.

Joining notes

  • Match the boundary vintage to the declaration year. Use county files from before 2022 for Connecticut declarations.
  • Virginia's independent cities are counties in FIPS terms and join normally.
  • Expanded statewide rows are an assumption: the declaration covered the whole state, but damage did not.
  • Puerto Rico's municipios are county equivalents (72xxx) and join if the boundary file includes Puerto Rico.

FAQ

What does fipsCountyCode 000 mean in FEMA data?

That the designated area is not a single county: a statewide designation, a tribal nation or a statistical area. 1,612 declaration rows have it.

How do I map statewide FEMA declarations?

Expand each statewide row to every county in its state before joining; the 464 statewide rows become 45,820 county rows.