Troubleshooting

weewx-nws manual · weewx-nws on GitHub · Report an issue


Start with the log

weewx-nws is talkative. Every download, every rejection and every save is logged under user.nws, and that is where nearly every question is answered:

grep 'user.nws' /var/log/syslog

At startup you should see the version, the binding, and — unless the URLs are hard coded — the gridpoint lookup:

INFO user.nws: Service version is 6.0.
INFO user.nws: Using binding 'nws_binding' to database 'nws.sdb'
INFO user.nws: request_urls: twelveHourForecastUrl: https://api.weather.gov/gridpoints/MTR/92,88/forecast

Then, from the poller threads, a Downloading line and a Downloaded line per type, and at the end of each archive period a Saved line when a new forecast arrived.

$nwsforecast prints as literal text

The report does not have the search list extension. Add it to that report’s stanza:

[StdReport]
    [[SeasonsReport]]
        [[[CheetahGenerator]]]
            search_list_extensions = user.nws.NWSForecastVariables

Both lines may need adding, and an existing search_list_extensions takes this as another comma-separated entry rather than being replaced. See Configuration.

The pages are empty, or a loop produces nothing

The tags return an empty list rather than failing, so an empty page means the database has no current forecast. In order of likelihood:

  1. It has not saved one yet. Forecasts are downloaded at startup but written to the database at the end of the next archive period, and the pages are generated after that. Give it two archive intervals.
  2. The downloads are failing. Look for Downloaded lines. If they are absent, look for the failures — see below.
  3. The station’s coordinates changed. Rows are stored with the latitude and longitude they were fetched for, and reads match on them. Change either, and the next save prunes the old rows and stores new ones; between those two moments the tags return nothing.
  4. The database is elsewhere. Confirm with the Using binding line, and look at what is in it: --view-forecasts with --view-criterion SUMMARY.

sanity check failed

INFO user.nws: request_forecast(ForecastType.ONE_HOUR): sanity check failed(https://...): ...

NWS returned json that does not have the shape weewx-nws requires, so it was rejected whole rather than half-parsed into the database. The raw response is logged with it — that text is the evidence, so keep it.

Nearly always this is NWS having a bad few minutes, and the next poll succeeds. If it persists, NWS has changed something: run --test-requester for your location to see the current response, and please open an issue with the logged text.

does not fall within bounds of forecast's polygon

WARNING user.nws: Lat/Long 37.431495/-122.110937 does not fall within bounds of forecast's polygon (due to NWS Bug).

NWS mapped your coordinates to a neighboring grid square. The forecast is still used. See Gridpoints for the check and the fix — and note that if you are seeing this with hard-coded URLs in weewx.conf, the override is now the problem.

404 and 503 from NWS

INFO user.nws: request_forecast(ForecastType.ONE_HOUR): 503, Forecast Grid Expired, ...
INFO user.nws: request_urls: 404, Data Unavailable For Requested Point, ...
  • Forecast Grid Expired is NWS’s own grid having gone stale. It clears without intervention; weewx-nws retries and goes on serving the stored forecast meanwhile.
  • Data Unavailable For Requested Point means NWS does not forecast for those coordinates. Check [Station] in weewx.conf — most often the longitude has lost its minus sign.
  • Every request failing at once is NWS being unwell rather than your station. Wait it out. Do not shorten poll_secs to compensate: NWS rate-limits, and can block a source that asks too often — which is also why a User-Agent that identifies you is worth setting, since it gives them someone to contact instead.

weewx-nws needs a SQLite database

ERROR user.nws: weewx-nws needs a SQLite database, but binding 'nws_binding' uses weedb.mysql.  Point [NWS] data_binding at a SQLite database …

weewx-nws stores its forecasts in a SQLite database of its own and cannot use any other kind: its schema declares STRING columns, which WeeWX passes to the database verbatim and MySQL has no such type. Point [NWS] data_binding back at a SQLite binding — the nws_binding / nws_sqlite entries the installer writes are one — and restart.

The extension does nothing until then, but WeeWX itself goes on running. Before 6.1.1 this surfaced as a raw MySQL syntax error while the service was starting, which stopped weewxd altogether.

The nws database has an old schema; rebuilding it

INFO user.nws: The nws database has an old schema (startTime is NOT NULL and should be nullable, endTime is NOT NULL and should be nullable); rebuilding it.
INFO user.nws: Rebuilt archive with the current schema.  The next poll of each forecast type will repopulate it.

Not a problem, and nothing to do. The database was created by an older release whose schema differed; there is no migration, so weewx-nws drops the table and lets WeeWX recreate it from the current schema. Nothing is lost that the next poll does not replace — no page reads a row older than the current forecast. You will see this once, on the first start after an upgrade that changed the schema.

Before 6.1 this was an error telling you to delete nws.sdb yourself, and the extension did nothing at all — no polling, no saving, no tags — until you did.

If the rebuild itself cannot be done, that is an error, and the old advice applies:

ERROR user.nws: Could not drop table archive to rebuild it: ...  Delete the nws database by hand and restart weewx.

Stop WeeWX, delete nws.sdb (it sits with the weather archive — commonly /var/lib/weewx/ on a package install, ~/weewx-data/archive/ on a pip one), and start it again. See Upgrading.

No alerts appear when there should be

  • Check that NWS has one for your point, not just for your county or state: https://api.weather.gov/alerts/active?point=<lat>,<long> in a browser, or --test-requester --type ALERTS. An alert covering your area but not your coordinates does not apply.
  • The alert may be a test. Test, exercise, system and draft alerts are skipped, with a line in the log saying which: Skipping alert with status of 'Test'.
  • It may have been superseded. An alert named in a newer alert’s expiredReferences is dropped: found expired alert (skipping).

An alert stays after NWS has dropped it

It should not, and mostly it does not: a download that finds no alerts clears them all. But an alert whose message expired is deliberately kept for up to a day, because NWS regularly lets one expire before issuing its replacement. It goes for good once its ends time has passed. See How it works.

The pages look unstyled, or the day tabs do nothing

The sample report’s stylesheet and script are copied into HTML_ROOT by the skin’s CopyGenerator, separately from the pages themselves. If they did not arrive, the pages render as plain unstyled text, and the hourly page shows every day at once because nothing is binding the tabs.

Check that both are there, next to the generated pages:

ls <HTML_ROOT>/nws/css/nws.css <HTML_ROOT>/nws/scripts/nws.js

If they are missing, the usual causes are a skin.conf whose generator_list lost weewx.reportengine.CopyGenerator, or a permissions problem on HTML_ROOT that the WeeWX log will have complained about. Both files are copied fresh on every report cycle, so a restart is enough once the cause is fixed.

With javascript blocked or unavailable the pages are still readable: the first paint is correct, the hourly page shows its first day, and only the tab switching and the chart crosshair are lost.

Dark mode does not come on

The pages follow prefers-color-scheme, which is the appearance setting on the reader’s device — not a setting in weewx.conf and not something the station chooses. There is deliberately no toggle on the page. If a page stays light, the browser is reporting a light preference; set the device to dark, or to an automatic mode that switches at sunset, and reload. If it stays light with the device set to dark, the stylesheet is probably the one missing above.

The wind reads $hour.windSpeed2 on the page

A missing $ in a template. With #errorCatcher Echo, Cheetah writes the template text into the page instead of raising, so a $ in your generated HTML is always a template bug — look for the placeholder it names. See Wind speed comes in two parts.

WeeWX will not shut down

Fixed in 5.1: a SIGTERM landing inside weewx-nws’s startup or save code was logged and swallowed instead of being passed through. If you are on an earlier release, upgrade.

Still stuck

Run --test-requester with your station’s latitude and longitude, and open an issue with what it prints and the user.nws lines from your log.


weewx-nws is Copyright © 2020–2026 John A Kline and is licensed under the GNU Public License v3.