The Texas Comptroller publishes a spreadsheet with the tax rate of all 254 counties and a second one with more than 4,800 local taxing units. I use both to estimate property tax bills, so a wrong rate turns directly into a wrong number on a page.

The 2025 county file says Fort Bend County's rate is $0.824 per $100 of taxable value. The rate the county actually adopted is $0.412. On a home with $300,000 of taxable value, that is a $1,236 difference in the county line of the bill.

The file is labeled "Working" and dated 01/28/2026, so this isn't a complaint about the Comptroller. It's a report built from what thousands of local units submit. But it is the kind of error a data pipeline will happily carry through, and the interesting part is which checks catch it.

Check 1: do the parts add up?

A Texas county rate has three parts: general fund, road and bridge, and farm-to-market/flood control (FMFC). The obvious first check:

import pandas as pd TOTAL = "TOTAL COUNTY TAX RATE" NNR = "NO-NEW-REVENUE RATE" VAR = "VOTER-APPROVAL RATE" def load(path): df = pd.read_excel(path, header=2) df = df[df["COUNTY ID"].notna()].copy() df["county"] = df["COUNTY NAME"].str.replace("*", "", regex=False).str.strip() return df.set_index("county") now = load("2025-county-rates-levies.xlsx") last = load("2024-county-rates-levies.xlsx") now["prev"] = last[TOTAL] parts = now[["GF TOTAL RATE", "R&B TOTAL RATE", "FMFC TOTAL RATE"]].fillna(0).sum(axis=1) print(((parts - now[TOTAL]).abs() > 0.0005).sum()) # 0 

Zero mismatches across 254 counties. Fort Bend's row looks like this:

Column Value
General fund 0.412
Road and bridge 0.024
FMFC 0.388
Total 0.824

The parts add up perfectly, because the error happened before the addition. The general fund block alone equals the county's whole rate, and road and bridge plus FMFC equals it again. The real split, from the county's adopted budget, is 0.278 general, 0.024 road and bridge, 0.110 debt service.

The file's calculated levy doesn't help either. It says $1,168,424,411, and recomputing it from the file's own taxable values and rates matches within a dollar. A derived column can't disagree with the numbers it was derived from.

Lesson: internal consistency proves the arithmetic, not the inputs.

Check 2: did it change from last year?

The usual next step is year-over-year change:

yoy = now[TOTAL] / now["prev"] - 1 print((yoy.abs() > 0.15).sum()) # 41 

Fort Bend moved by exactly 0%. The 2024 file has the same doubling, 0.824 in both years. A check against history can only find new errors. A repeated error looks like stability.

This check is also noisy. 41 of 254 counties moved more than 15%, and many of those are real: tax rate elections, new debt, reappraisals. Still, it did catch things the first check couldn't, as the table below shows.

Check 3: compare against an independent number

The file has two more columns that are easy to skip past. Texas truth-in-taxation rules require each unit to calculate a no-new-revenue rate (the rate that would raise about the same money as last year on the same properties) and a voter-approval rate (the most it can adopt without an election).

These don't come from the adopted rate, so they can disagree with it. Most counties land close to the no-new-revenue rate: the median ratio is 1.04.

ref = now[NNR].where(now[NNR] > 0) ratio = now[TOTAL] / ref print(now[(ratio > 1.5) | (ratio < 0.6)].index.tolist()) 

Fort Bend comes out at 1.97. A county adopting nearly double its no-new-revenue rate, with no tax election, is not plausible. After that it took one look at the county's adopting order to settle it.

The ratio has to be two-sided. A rate that is too low is an error as well, and ratio > 1.5 alone would miss it.

What each check caught

These are the five corrections I ended up making. Each was confirmed against a source outside the file:

Unit File Correct Sum of parts Year over year vs. no-new-revenue
Fort Bend County 0.824 0.412 passed passed (0%) flagged (1.97×)
Van Zandt County 0.6992 0.3996 passed flagged (+129%) flagged (1.86×)
Wise County 0.2175 0.265 passed flagged (−21%) passed (0.84×)
City of Austin 0.574017 0.524017 n/a flagged (+20%) n/a
City of McAllen 0.076532 0.448989 n/a flagged (−83%) n/a

No single check finds all five, and the sum check finds none. What happened in each case:

  • Van Zandt repeats the 0.2996 general fund rate in the FMFC column, so the total picks it up twice. Commissioners adopted $0.3996.
  • Wise is missing a piece. The file has the 21.75 cent general fund rate, but the county's rate was 26.5 cents with road and bridge. The 2024 file had a second component of 4.75 cents, and the 2025 file doesn't.
  • Austin is my favorite, because the number isn't a typo. 0.574017 was a real proposal: the rate that needed voters to pass Proposition Q. Voters rejected it on November 4, 2025, and the rate fell to the voter-approval level of 0.524017. The file still has the rejected rate. It only barely tripped the 20% threshold I use for cities, at +20.2%.
  • McAllen went from 0.449989 to 0.076532 in the file, while the city's own 2025 notice lists 0.448989. I don't know where 0.0765 came from.

The reference columns have errors too

Fourteen counties land outside the 0.6 to 1.5 range. Only two of those are in the table above, so most flags are not confirmed errors in the adopted rate. The reference values need the same suspicion:

  • In Fayette, Comanche and Knox, the general fund rate matches the voter-approval rate almost to the digit, with a road and bridge rate on top. It looks like the reference figures cover only part of the levy there, which would make these false alarms.
  • Childress has a no-new-revenue rate of 0.021114 next to a voter-approval rate of 0.602082. Archer's voter-approval rate is 0.02968 next to a no-new-revenue rate of 0.50184. (Archer isn't one of the fourteen, because this check only reads the no-new-revenue column.) Those look like bad reference values, not bad adopted rates.
  • Ten counties, including Tarrant, have a blank or zero no-new-revenue rate, so the check simply can't run for them. A check that silently skips rows should say how many it skipped.

One more cheap test came out of this: look for exact factors of two. Duplication errors leave that signature, and real budgets almost never do.

for col in (NNR, VAR, "prev"): r = now[TOTAL] / now[col].where(now[col] > 0) print(col, r[((r - 2).abs() < 0.0005) | ((r - 0.5).abs() < 0.0002)].round(3).to_dict()) 

That returns three counties. Travis has a voter-approval rate of exactly twice its adopted rate. Mason's 2024 rate is exactly twice its 2025 rate. Jeff Davis shows 1.3735, exactly twice its voter-approval rate of 0.68675, and more than double last year's 0.64359.

I haven't been able to confirm any of those three yet, or Baylor (+113%), or Culberson (a rate of 0). They could be errors or they could have a real explanation, and a small county's budget PDF can take a while to find. So they're open items on a list, not corrections. A flag is a question, and it only becomes a fix once a source outside the file answers it.

What I'd keep from this

  1. Rank your checks by independence, not convenience. A check is only as good as how separate its inputs are from the value being tested. Sum of parts and derived totals share inputs with it. Statutory reference rates don't.
  2. History can't see persistent errors. Fort Bend was wrong in two consecutive files, and that made it look stable.
  3. Keep corrections in data, not code. Mine live in a JSON file that the build applies on top of the raw download, and each entry has a note naming its source. When next year's file arrives, I can see what was changed and why, and whether the fix is still needed.
  4. Never auto-correct from a flag. "Halve anything near 2×" would have fixed Fort Bend and might have broken a real tax increase elsewhere. Every change in that file was checked by hand.
  5. Report what you skipped. Ten counties have no reference value, and in those a doubled rate could only surface through the year-over-year check.

The corrected rates are what appears on the site, for example on the Fort Bend County page, with the file's other local rates alongside them.