cur-athena-lint
Check AWS Cost and Usage Report Athena SQL for the mistakes that inflate your query bill and silently produce wrong numbers — without an AWS account.
pip install cur-athena-lint # from PyPI, Python 3.9+
cur-athena-lint # run the 16 checks over the SQL that ships with it
Or from a clone — the same code either way:
git clone https://github.com/duke5am/cur-athena-lint
cd cur-athena-lint
python3 verify_pack.py # the 16 structural checks
python3 parse_all_sql.py # the grammar sweep on its own
The seventeen SQL files ship inside the package, so the installed checker verifies them with no checkout and no extra download.
$ cur-athena-lint
sqlglot : 26.16.4 dialect: athena
Verified cols: 80 names on the allow-list
[PASS] P02 every .sql file parses as Athena dialect 17/17 parsed; no errors
[PASS] P03 no query uses SELECT * 10 COUNT(*) aggregates, all fine
[PASS] P04 every statement reading the CUR table filters on year AND month
[PASS] P04b no CTE or subquery reads the CUR table without a partition filter either
[PASS] P06 every column reference is on the verified column allow-list
[PASS] P07 every column the queries use is also declared in setup/create_table.sql
RESULT: 15/15 structural checks passed, 0 failed
Exit codes: 0 every check passed · 1 at least one check failed · 2 nothing
was checked (CUR_CONTENT does not exist) · 3 internal failure.
To point the checker at a different tree, set CUR_CONTENT. Note that the two
pack-integrity checks (P12 manifest, P15 README counts) then fail unless that
tree also ships a REQUIRED_FILES.txt and the pack README.
Why CUR SQL goes wrong
The CUR table is a 100+ column monster where cost is split across many columns and the obvious one is usually the wrong one. Three failures are common:
You scan a year of data to answer a question about one month. The table is
partitioned by year/month, and a missing predicate means Athena reads
everything. This checker requires both predicates on every CUR-reading
statement — including inside CTEs, because a subquery that scans unpruned is just
as expensive.
You use the wrong cost column. line_item_unblended_cost is not the number
you want for most questions, and for EC2/RDS line items with a reservation
applied it is 0 — the cost lives in reservation_effective_cost. Summing the
wrong column gives you a confident, wrong total.
You double-count a discount. Savings Plan covered usage is recorded at
on-demand list price and offset by a separate SavingsPlanNegation line. Count one
without the other and your January total is inflated — by exactly the negation
amount, which can be substantial.
What the checker enforces
- every
.sqlfile parsed with sqlglot'sathenadialect — a real grammar, not a regex - no
SELECT *(withCOUNT(*)correctly allowed — it reads no columns) yearANDmonthon every CUR-reading statement, including CTEs and subqueries- no function wrapping a partition column in
WHERE(that defeats pruning) - every column reference against an 80-name verified allow-list
- internal consistency between the queries and the shipped
CREATE EXTERNAL TABLE - a header comment with a bytes-scanned warning on every query
What it does NOT check
Stated by the tool itself, not buried: no query here was executed against
Athena, no CUR data was read from S3, and no output was compared to Cost
Explorer. Column existence is asserted from AWS documentation, not from a live
DESCRIBE. Bytes scanned and cost are not measured.
Only your own INFORMATION_SCHEMA can tell you a column exists in your dataset.
The queries
Fifteen analysis queries answering one question each — cost by service, account, resource and tag; month-over-month movers with contribution to change; anomaly detection against a trailing baseline; RI/SP coverage and unused commitment; data transfer; S3 storage and requests; and a partition-pruned variant that proves pruning changes cost, not answers.
CUR-SCHEMA.md explains the line_item_* cost columns and the
line_item_line_item_type values that decide whether you double-count.
Setup
pip install cur-athena-lint # pulls sqlglot, the only dependency
cur-athena-lint
From a clone without installing anything:
apt install python3-sqlglot # or: pip install sqlglot
python3 verify_pack.py
Requires sqlglot only. Refresh the DDL with cur_athena_lint/setup/create_table.sql.
The full pack
The paid pack adds COST-CONTROL-ATHENA.md, VALIDATION.md (how to prove a query
against Cost Explorer before trusting it), the reconciliation query, and the
synthetic-CUR validation harness.
Related tools
- bank-csv-reconcile — Turn a bank CSV or Excel export into one clean table and reconcile the running balance, so a dropped row shows up instead of silently changing totals. (if you were searching for "bank statement csv to excel")
- ga4-bigquery-lint — Lint GA4 BigQuery SQL for the session, event_params and cost mistakes that quietly give you wrong numbers, using sqlglot's real BigQuery grammar. (if you were searching for "ga4 bigquery queries")
All 28 tools in this set, grouped by what they check: dev-tools-index
If you arrived here searching for one of these, this is the tool: aws cur athena query · cost and usage report sql · athena partition pruning cost · aws cost anomaly query
→ More developer tooling like this: duke5am.gumroad.com
Release files for cur-athena-lint 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| cur_athena_lint-0.1.0.tar.gz | 66.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| cur_athena_lint-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 129.0 kB
Release files / cur_athena_lint-0.1.0.tar.gz
| Download URL | cur_athena_lint-0.1.0.tar.gz |
|---|---|
| Size | 66.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ebcebf5a51555e23795bd0ae83b671b1ef32c595c1062e8848e16fe971164870
|
|
BLAKE2b-256 checksum How to use checksums |
a4f40799537b75bd9e72ba898a81a034e1e002cf55abb93e61086a84e6825076
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.5
|
Release files / cur_athena_lint-0.1.0-py3-none-any.whl
| Download URL | cur_athena_lint-0.1.0-py3-none-any.whl |
|---|---|
| Size | 62.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
152dbc67f1342d1904c66f7c1c912a6b77f4e17947d91289cd379b147ce04c54
|
|
BLAKE2b-256 checksum How to use checksums |
1c4da12412ca799181afe448c91f3990be091f2dee76218e3c79b95e755c85b0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.5
|