Repository navigation
fix(billing-cost-management-mcp-server): point a filtered forecast's no-data error at the filter - #4940
Merged
finklen-amazon merged 6 commits intoNov 1, 2026
Conversation
finklen-amazon
requested review from
a team,
Comusus,
Rahul-1404,
anniewn,
bhatia-di,
callnmm,
chittev,
johnwangwyx,
junaidgirkar,
mattkelsey,
shsrams,
somsubhro,
wangyuhere and
yasmeenh11
as code owners
October 29, 2026 00:10
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4940 +/- ##
=======================================
Coverage 93.79% 93.79%
=======================================
Files 1080 1080
Lines 94586 94597 +11
Branches 15402 15403 +1
=======================================
+ Hits 88715 88726 +11
Misses 3498 3498
Partials 2373 2373 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
finklen-amazon
force-pushed
the
fix/bcm-forecast-no-match-hint
branch
from
October 30, 2026 00:02
c24cb72 to
a9cf4f0
Compare
anniewn
previously approved these changes
Oct 30, 2026
…no-data error at the filter Cost Explorer returns DataUnavailableException "Insufficient amount of historical data." both when there is too little history and when a forecast filter as a whole matches no past costs: a misspelled value, the wrong case, a value from another dimension, or a partial value with STARTS_WITH, CONTAINS or CASE_INSENSITIVE, which the service accepts but does not apply (the API reference says MatchOptions applies only to cost category and anomaly subscription actions). The shared DataUnavailable hint names an unmatched filter as one possible cause, but maps to do_not_retry, and the forecast notes described only the history case, so a caller with a mistyped filter concluded that no forecast was possible. - getCostForecast and getUsageForecast: when a filter was sent and the service returns DataUnavailableException, set retry_strategy to modify_request with a hint not to resend the same request, to check the values with getDimensionValues, getTagsOrValues or getCostCategories, and to report too little history only if the values exist and can occur together. Without a filter the shared do_not_retry guidance is unchanged. - Forecast notes: filter values match exactly, including case; those MatchOptions are accepted but not applied; an unmatched filter returns the same error as too little history.
finklen-amazon
force-pushed
the
fix/bcm-forecast-no-match-hint
branch
from
October 30, 2026 01:47
a9cf4f0 to
37ef5cc
Compare
Resolve conflicts with main: - cost_explorer_tools.py getUsageForecast: take main's Example 3 (one Region filter instead of group_by, which forecasts now reject) and keep this branch's added Notes sentence on unmatched filters. - test_cost_explorer_tools.py: keep both sides' appended tests. - test_cost_explorer_operations.py: an empty filter is now a validation_error on main, so the unfiltered guard uses None only, and a new test checks that an empty filter never gets the no-match hint.
…ck in the forecast hint Use 'filters is not None', as main now does when deciding to send Filter, and check the empty-filter test through add_retry_guidance.
… on a sent filter Revert the previous commit's 'filters is not None' check to 'if filters'. parse_filter already rejects empty filters, so both forms send the hint for the same requests; the truthy form is the one already reviewed.
anniewn
approved these changes
Oct 30, 2026
finklen-amazon
enabled auto-merge
October 30, 2026 17:26
yasmeenh11
approved these changes
Oct 30, 2026
Pick up main's DynamoDB rec-details test fix so CI re-runs. No conflicts.
github-merge-queue
Bot
removed this pull request from the merge queue due to failed status checks
Oct 30, 2026
finklen-amazon
enabled auto-merge
October 30, 2026 20:30
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes
Summary
Cost Explorer returns
DataUnavailableException: Insufficient amount of historical data.in two cases: when there is too little history to forecast, and when the forecast filter as a whole matches no past costs. That covers a misspelled value, the wrong case, a value from another dimension, or a partial value used withSTARTS_WITH,CONTAINSorCASE_INSENSITIVE. The service accepts those MatchOptions but does not apply them; the DimensionValues reference says MatchOptions applies only to cost category and anomaly subscription actions.The shared
DataUnavailableExceptionhint already names an unmatched filter as one possible cause, but it maps todo_not_retry. The forecast notes described only the history case. So a caller with a mistyped filter was told not to retry and reported that no forecast was possible, while the same account forecasts fine with a correct filter.Changes
getCostForecast/getUsageForecast: when a filter was sent and the service returnsDataUnavailableException, the response now hasretry_strategy: modify_requestand a forecast-specific hint: do not resend the same request; check the values withgetDimensionValues(getTagsOrValuesfor tags,getCostCategoriesfor cost categories) and retry with corrected values; if the values exist and can occur together, report that there is too little history. Without a filter, the shareddo_not_retryguidance is unchanged.No tool, parameter or schema is renamed or removed.
User experience
Before:
{"operation": "getCostForecast", "metric": "UNBLENDED_COST", "granularity": "MONTHLY", "filter": {"Dimensions": {"Key": "SERVICE", "Values": ["Amazon Elastic Compute Cloud - Compte"]}}}returnedDataUnavailableException"Insufficient amount of historical data." withretry_strategy: do_not_retry, and an agent reported that the account cannot be forecast.After: the same call returns the same
error_typeandmessage, withretry_strategy: modify_requestand a hint to check the filter values first. Unfiltered calls are unchanged.Testing
do_not_retry, an empty filter ({},'{}') is avalidation_errorwithout the hint, and other errors with a filter are unchanged. 246 tests in the two touched test files pass; ruff and pyright are clean.SERVICEfilter forecasts successfully (control); a one-letter typo, aSTARTS_WITHpartial value and a misspelledUSAGE_TYPE_GROUPeach returnDataUnavailableExceptionwithmodify_requestand the new hint.do_not_retrywith the generic hint). Only the valid-filter control passed.CONTAINSandCASE_INSENSITIVEare ignored (same error); a value from another dimension, a misspelled tag value and the wrong case match nothing;Notof a misspelled value andOrof a valid and a misspelled value both forecast normally.Merge conflict
#4919 merged as a squash commit, so this branch, which was stacked on #4919's branch, conflicted with
mainincost_explorer_operations.pyandcost_explorer_tools.py: the forecast lines #4919 changed showed up as edits to the same lines this PR extends. I rebased this PR's single commit ontomain, dropping #4919's commits, which are now upstream. The commit applied with no manual edits. #4919'speriod_notetext and helper are kept as merged, and this PR's changed lines are identical to the reviewed revision. Unit tests (3252), ruff and pyright pass on the rebased branch.After this PR was approved, #4936 merged and added its billing_view_arn tests at the end of
tests/tools/test_cost_explorer_tools.py, where this PR adds its forecast-notes test, so the branch conflicted withmainagain. I rebased ontomainand kept both: #4936's tests unchanged, followed by this PR's test. No source or tool text conflicted, and this PR's changed lines are identical to the approved revision. Unit tests (3442), ruff and pyright pass on the rebased branch.Main then moved again and this branch conflicted a third time. This time I merged
maininto the branch (a merge commit, no force-push):cost_explorer_tools.py, getUsageForecast: fix(billing-cost-management-mcp-server): reject group_by where Cost Explorer has no GroupBy and document filter limits #4964 replaced Example 3 (group_by is now rejected on forecasts) while this PR extended the Notes line. I kept fix(billing-cost-management-mcp-server): reject group_by where Cost Explorer has no GroupBy and document filter limits #4964's Example 3 and this PR's Notes line.tests/tools/test_cost_explorer_tools.py: both sides added tests at the end of the file; I kept both.tests/tools/test_cost_explorer_operations.py(no text conflict): fix(billing-cost-management-mcp-server): reject an empty filter instead of dropping it #4962 now rejects an empty filter with avalidation_errorbefore any call. This PR's unfiltered guard had used{}and'{}'as "no filter", so it now usesNoneonly, and a new test checks that an empty filter gets thevalidation_errorand never the no-match hint.The tool code of this PR is unchanged. The live check passes 5 of 5 on the merge, and the follow-up commits change only that empty-filter test. The touched tests, ruff and pyright pass. One test in
test_recommendation_details_tools.pyfails onmaintoo, without this PR.Checklist
If your change doesn't seem to apply, please leave them unchecked.
Is this a breaking change? (Y/N) N
Acknowledgment
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of the project license.