How to Find Scour-Critical Bridges Over Rivers
On this page
Problem statement
Most bridges that collapse in the United States are not brought down by traffic or age but by water: floods scour away the riverbed around piers and abutments until the foundation is undermined. The National Bridge Inventory records each bridge's vulnerability to scour in item 113, a single character from 0 to 9 plus N, U and T. This guide decodes it for the 2025 inventory, counts the bridges rated scour critical and those whose foundations are unknown, finds where they are and how much traffic they carry, and relates scour to condition.
Quick answer
Codes 0 to 3 of SCOUR_CRITICAL_113 mean scour critical: the foundation is, or could become, unstable under scour. N means the bridge is not over water; U means the foundation is unknown, so scour cannot be assessed. Count and map those, and keep U separate from both groups.
sc = nbi.SCOUR_CRITICAL_113.str.strip()
critical = sc.isin(["0", "1", "2", "3"])
water = sc != "N"
print(f"bridges over water (item 113 not N): {water.sum():,}; scour critical (codes 0-3): {critical.sum():,} ({critical[water].mean():.1%} of those over water)")
print("item 113 codes:", sc.value_counts().reindex(list("9876543210UTN")).fillna(0).astype(int).to_dict())
bridges over water (item 113 not N): 516,090; scour critical (codes 0-3): 19,775 (3.8% of those over water)
item 113 codes: {'9': 2457, '8': 318860, '7': 12576, '6': 3888, '5': 110059, '4': 24218, '3': 18949, '2': 685, '1': 56, '0': 85, 'U': 24250, 'T': 7, 'N': 108103}
Of 516,090 bridges over water (item 113 other than N), 19,775 are scour critical β 3.8%. Most bridges over water are rated stable (codes 8 and 5); 24,250 have unknown foundations (U).
Decoding item 113
1. What the codes mean
SCOUR = {"N": "not over water", "U": "unknown foundation", "T": "tidal, not evaluated", "9": "on dry land", "8": "stable, above footing",
"7": "countermeasures installed", "6": "not yet evaluated", "5": "stable, within footing", "4": "stable, action needed",
"3": "critical: unstable", "2": "critical: extensive scour", "1": "critical: failure imminent", "0": "failed, closed"}
t = sc.map(SCOUR).value_counts()
print(t.to_string())
SCOUR_CRITICAL_113
stable, above footing 318860
stable, within footing 110059
not over water 108103
unknown foundation 24250
stable, action needed 24218
critical: unstable 18949
countermeasures installed 12576
not yet evaluated 3888
on dry land 2457
critical: extensive scour 685
failed, closed 85
critical: failure imminent 56
tidal, not evaluated 7
The codes run from 9 (on dry land, above flood water) through 8 (stable, foundations above the scour depth) and 5 (stable, scour within the footing) to 3 (unstable for assessed scour), 2 (extensive scour has occurred), 1 (failure imminent) and 0 (failed and closed). Code 7 means countermeasures β riprap, sheet piling β have been installed after a problem was found; 12,576 bridges have them.
2. Unknown foundations
print(f"unknown foundations (U): {(sc == 'U').sum():,}; not yet evaluated (6): {(sc == '6').sum():,}")
print(f"daily crossings on scour-critical bridges: {nbi.loc[critical, 'adt'].sum() / 1e6:,.1f} million; on unknown-foundation bridges: {nbi.loc[sc == 'U', 'adt'].sum() / 1e6:,.1f} million")
unknown foundations (U): 24,250; not yet evaluated (6): 3,888
daily crossings on scour-critical bridges: 76.4 million; on unknown-foundation bridges: 36.9 million
24,250 bridges have foundations nobody can document β usually older bridges whose plans are lost β and 3,888 are over water but not yet evaluated. Scour-critical bridges carry 76.4 million vehicle crossings a day and unknown-foundation bridges another 36.9 million.
3. Where they are
st = critical.groupby(nbi.state).sum().sort_values(ascending=False)
print("scour-critical bridges by state, most:", st.head(6).to_dict())
share = critical.groupby(nbi.state).sum() / water.groupby(nbi.state).sum()
print("share of a state's water crossings that are critical, highest:", share.sort_values(ascending=False).head(5).round(3).to_dict())
scour-critical bridges by state, most: {'PA': 2249, 'LA': 1302, 'OR': 1225, 'SC': 1217, 'MI': 1077, 'NE': 986}
share of a state's water crossings that are critical, highest: {'PR': 0.271, 'RI': 0.249, 'OR': 0.172, 'SC': 0.15, 'MI': 0.129}
Pennsylvania has the most scour-critical bridges (2,249), then Louisiana, Oregon, South Carolina and Michigan. As a share of water crossings, Puerto Rico (27.1%) and Rhode Island (24.9%) lead, with Oregon at 17.2%. Rating practice differs between states β how conservatively each assesses scour β as well as rivers and geology.
4. Critical and poor
print(pd.crosstab(critical, nbi.cond, normalize="index").round(3).rename(index={True: "scour critical", False: "not critical"}).to_string())
cond F G P
SCOUR_CRITICAL_113
not critical 0.492 0.447 0.060
scour critical 0.610 0.124 0.266
Scour-critical bridges are far more often poor: 26.6% against 6.0% of other bridges, and only 12.4% are good. Scour damage shows up in the substructure rating, which then sets the bridge's condition.
What they cross, and the failed ones
The data used on this page
The Federal Highway Administration's National Bridge Inventory for 2025, the scour-critical item, coded as in FHWA's Recording and Coding Guide, and Census Bureau 2023 states.
import zipfile
from pathlib import Path
import geopandas as gpd
import numpy as np
import pandas as pd
import requests
Path("data").mkdir(exist_ok=True)
# FHWA National Bridge Inventory, 2025 submission, highway bridges, all states in one comma-delimited file (53 MB zip).
# The server is slow and drops long downloads, so resume until the file is complete.
URL = "https://www.fhwa.dot.gov/bridge/nbi/2025hwybronefiledel.zip"
f = Path("data/2025hwybronefiledel.zip")
size = int(requests.head(URL, allow_redirects=True, timeout=60).headers["Content-Length"])
while not f.exists() or f.stat().st_size < size:
have = f.stat().st_size if f.exists() else 0
try:
with requests.get(URL, headers={"Range": f"bytes={have}-"}, stream=True, timeout=120) as r, open(f, "ab") as out:
for chunk in r.iter_content(1 << 20):
out.write(chunk)
except requests.RequestException:
pass # resume from what arrived
with zipfile.ZipFile(f) as z:
nbi = pd.read_csv(z.open("2025HwyBridgesDelimitedAllStates.txt"), quotechar="'", dtype=str, low_memory=False)
def dms(s, west=False):
"""NBI packs coordinates as DDMMSSss (latitude) and DDDMMSSss (longitude, positive west)."""
s = s.str.strip().str.zfill(9 if west else 8)
d = s.str[:-6].astype(float) + s.str[-6:-4].astype(float) / 60 + s.str[-4:].astype(float) / 100 / 3600
return -d if west else d
nbi["lat"], nbi["lon"] = dms(nbi.LAT_016), dms(nbi.LONG_017, west=True)
nbi["cond"] = nbi.BRIDGE_CONDITION # G, F or P, derived by FHWA
nbi["adt"] = pd.to_numeric(nbi.ADT_029, errors="coerce")
nbi["built"] = pd.to_numeric(nbi.YEAR_BUILT_027, errors="coerce")
nbi["area"] = pd.to_numeric(nbi.DECK_AREA, errors="coerce")
for name in ["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)
states = gpd.read_file("data/cb_2023_us_state_20m.zip").to_crs(4326)
nbi["state"] = nbi.STATE_CODE_001.map(states.set_index("STATEFP").STUSPS)
print(f"{len(nbi):,} highway bridges, {nbi.shape[1]} fields, {nbi.STATE_CODE_001.nunique()} state codes")
624,193 highway bridges, 130 fields, 53 state codes
Example 1: what crosses over
und = nbi.SERVICE_UND_042B.str.strip()
UND = {"5": "waterway", "6": "highway and waterway", "7": "railroad and waterway", "8": "highway, waterway and railroad", "9": "relief for waterway"}
print("scour-critical bridges by what they cross:", und[critical].map(UND).fillna("other").value_counts().to_dict())
scour-critical bridges by what they cross: {'waterway': 19329, 'relief for waterway': 190, 'highway and waterway': 145, 'railroad and waterway': 61, 'highway, waterway and railroad': 45, 'other': 5}
Almost all scour-critical bridges cross a waterway alone (19,329); a few also cross a road or railway, and 190 are relief bridges that carry a road over floodplain only in high water.
Example 2: the failed ones
f0 = nbi[sc == "0"]
print(f"code 0 (bridge failed, closed): {len(f0)}; status 'K' closed among them: {(f0.OPEN_CLOSED_POSTED_041 == 'K').mean():.0%}")
code 0 (bridge failed, closed): 85; status 'K' closed among them: 71%
85 bridges are coded 0, failed. 71% of them have status K, closed; the rest are coded otherwise in item 41, a reminder to cross-check one coded field against another before trusting either.
Why scour is its own rating
Scour is the leading cause of bridge failure in the United States, and it happens out of sight: during a flood the riverbed around a pier can drop several metres and refill afterwards, so a routine inspection at low water sees nothing. FHWA therefore asks for a separate engineering assessment of each bridge over water, and item 113 records the result. A scour-critical bridge must have a plan of action β monitoring during floods, closure triggers, countermeasures.
Scour-critical does not mean the bridge is unsafe today; it means its foundation could become unstable in a large enough flood. Combining item 113 with a flood hazard layer β which bridges are critical and also in a floodplain or on a river with rising peak flows β is the natural next step for a risk map.
Pitfalls with item 113
- Strip the code. Codes may carry spaces;
.str.strip()first. - U is not stable. Unknown foundations are a separate risk class; do not fold them into "not critical".
- T (tidal) is rare and means not evaluated in a tidal waterway.
- The new specification (SNBI) replaces item 113 with different fields; future files will need a crosswalk.
Internal links
- How to map the National Bridge Inventory β the file and its coordinates
- Flood hazard maps explained β the rivers that rise
- How to analyse load-posted and closed bridges β closures
FAQ
How many US bridges are scour critical?
19,775 in the 2025 National Bridge Inventory, 3.8% of bridges over water; another 24,250 have unknown foundations.
What does scour critical mean?
That the bridge's foundation is, or could become, unstable from erosion of the riverbed during floods (item 113 codes 0 to 3).