Two days ago we retracted a set of drought percentages that came from a hard-coded function of a Pacific index. In doing that we said our own rainfall feed was not trustworthy either, and promised to say why. Here is why. A single guard clause, true for every month of the year, made the code read the day of the month as the month. The comparison baseline collapsed to one earlier day. The feed is now rebuilt, and all eight regions are reporting monthly anomalies against multi-year baselines: ten years for seven regions, and the seven years currently available for East Africa.
On 7 August we published a correction retracting seven regional drought percentages that had gone out to subscribers. Those figures came from a step function of the Oceanic Niño Index with no rainfall data in it at all.
In the same post we said something less comfortable: the observed rainfall feed we were checking them against could not be trusted either. Every region read NEAR NORMAL, including one at −94 percent and one at +16,142 percent. We flagged the panel as under repair and promised the diagnosis. This is it, along with the numbers the feed now produces.
ClimateSERV returns dates as MM/DD/YYYY. Our worker extracted the month like this:
const m = p.length===3 && parseInt(p[0])<=31 ? parseInt(p[1])-1 : parseInt(p[0])-1;
Read the guard. Months are 1 to 12, so parseInt(p[0]) <= 31 is true for every month there is. The condition can never be false. So the expression always takes the first branch and returns p[1], which is the day.
For 06/30/2026 it computed month index 29. For 05/30/2026 it also computed 29, because both fall on the 30th.
The code then gathered "all other granules in the same month" to average as a climatology. But since the month had become the day number, "same month" meant "same day number".
The request window was about 61 days, 1 May to 30 June 2026. Across 61 days there is exactly one other granule numbered 30: 30 May.
IAMElNino.com analysis. So the field labelled climatology_mm held the rainfall on a single day, one month earlier. The "anomaly" was 30 June minus 30 May. We reconstructed the series and ran the worker's own expression against it, and it reproduces every published figure exactly: +0.5, +4.9, −4.9, −0.6, +1.5, +2.6, −4.0 and −2.4 mm.
Three consequences followed, and together they explain everything readers were seeing.
The obvious repair is to ask ClimateSERV for monthly sums instead of daily averages. We wrote that patch: change intervaltype from 0 to 1, and operationtype from 5 to 4.
Before deploying it we tested the parameters against the live API. That patch would have broken the feed completely.
| intervaltype | operationtype | granules returned |
|---|---|---|
| 0 (daily) | 5 (average) | 91 |
| 0 (daily) | 4 (sum) | 0 |
| 1 (monthly) | 4 (sum) | 0 |
| 0, 1, 2, 3 | 4 (sum) | 0 for all |
IAMElNino.com analysis, from live calls to the ClimateSERV API on 9 August 2026 between roughly 14:00 and 14:30 UTC, using a one-degree test polygon and a January to March 2024 window. For CHIRPS, the only combination that returns data is daily granules with a spatial average. Ask for a sum and ClimateSERV returns an empty array with progress 100 and no error. Ask for monthly and it does the same.
ClimateSERV's own documentation lists operation type 4 as "Sum" in its getParameterTypes response. For CHIRPS it does not honour it. The interval enumeration is not documented at all: the docs say it is "hardcoded in the mark up language of the current client".
Had we deployed that patch, the parser would have thrown "Empty data response" for every region, the feed would have gone dark, and we would have published a post saying it was repaired. The test took ten minutes.
The aggregation had to move into our worker rather than the request. Each granule is the spatial mean rainfall for one day in mm, so summing across a calendar month gives the monthly areal-mean total. The baseline comes from the same calendar month in prior years, fetched as separate requests and cached unless the source dataset or processing method changes.
Same eight regions, same day, same underlying CHIRPS rainfall product, which combines satellite estimates with station observations. The left side is what the site served on the morning of 9 August. The right side is what it serves now.
| Region | Old: value vs "baseline" | Old label | New: June 2026 total vs June normal | New label | Years |
|---|---|---|---|---|---|
| South Asia / India | 7 vs 7 mm (+7%) | NEAR NORMAL | 98 vs 116.4 mm (−15%) | NEAR NORMAL | 10 |
| Northern China | 5 vs 0 mm (+16,142%) | NEAR NORMAL | 81 vs 92.9 mm (−13%) | NEAR NORMAL | 10 |
| Northeast Brazil | 0 vs 5 mm (−94%) | NEAR NORMAL | 34 vs 36.9 mm (−8%) | NEAR NORMAL | 10 |
| Southern Africa | 0 vs 1 mm (−93%) | NEAR NORMAL | 9 vs 6.9 mm (+31%) | ABOVE NORMAL | 10 |
| Eastern Australia | 2 vs 1 mm (+267%) | NEAR NORMAL | 32 vs 27.3 mm (+18%) | NEAR NORMAL | 10 |
| Indonesia & SE Asia | 9 vs 7 mm (+39%) | NEAR NORMAL | 189 vs 240.2 mm (−21%) | NEAR NORMAL | 10 |
| Peru & Ecuador coast | 0 vs 4 mm (−92%) | NEAR NORMAL | 98 vs 137.9 mm (−29%) | MODERATE DEFICIT | 10 |
| East Africa (Horn) | 1 vs 3 mm (−71%) | NEAR NORMAL | 36 vs 52.9 mm (−32%) | MODERATE DEFICIT | 7 |
India is the clearest illustration of why nobody caught this. Seven against seven looks like a reading. It was one day against one day, and the fact that they nearly matched made it look like a region sitting comfortably at its normal. The real comparison is 98 mm of June rain against a 116.4 mm June average across ten years, 2016 to 2025.
Southern Africa illustrates why the new percentage guard matters. Its June baseline is only 6.9 mm, because June is deep in its dry season, so even a small absolute difference can produce a large percentage anomaly. It now returns +31 percent, a sensible statement about a dry month that was slightly wetter than usual. The earlier +16,142 percent occurred in Northern China, where the broken one-day baseline was approximately 0.03 mm.
Three regions show deficits exceeding 20 percent for June 2026: Indonesia and Southeast Asia at 21 percent below its ten-year June average, the Peru and Ecuador coast at 29 percent below, and East Africa at 32 percent below its seven-year average. Peru is worth noting because it is the site's designated flood region: the canonical El Niño signal on that coast is heavy rainfall, not dryness. India, Northern China and Northeast Brazil also sit modestly negative, between 8 and 15 percent below average.
Set against the alert we retracted, the picture is close to inverted. India was emailed at 78 percent drought risk and is 15 percent below normal, which is unremarkable. Southern Africa was emailed at 65 percent and came in wetter than usual. Indonesia and Southeast Asia was emailed at 80 percent and is the one large region genuinely dry, at −21 percent, which the ladder got right by accident rather than by measurement.
One caution on all of it. June is a single month, and for several of these regions it is not the month that matters. Southern Africa's rains do not begin until October, so a June reading there says almost nothing about the season FEWS NET is actually worried about. A monthly anomaly is an observation, not a seasonal outlook.
A guard clause that could never be false made a date parser read the day as the month. That turned a climatology into a single earlier day, turned percentages into divisions by near-zero, and pushed every region into the same label because the thresholds assumed a different unit. None of it threw an error, which is why it survived.
The repair is deployed and all eight regions now report monthly totals against a real multi-year baseline. We also nearly shipped a fix that would have silently emptied the feed, and only caught it because we tested the API parameters instead of trusting the documentation. That is the more useful lesson of the two.