# weatherapi Troubleshooting

Use this guide to separate startup, database, template, request-validation, and
no-data problems. For full command and configuration reference, see
[`docs/cli.md`](cli.md) and [`docs/config.md`](config.md).

## Startup Fails with `load config`

Symptom: the process exits and logs `weatherapi failed: load config: ...`.

Likely causes:

- the config path is wrong;
- the process working directory is not where `config.yml` is expected;
- YAML syntax is invalid;
- required feedapi config fields are missing.

Diagnostic:

```sh
ls -l config.yml
python3 -c 'import yaml; yaml.safe_load(open("config.yml"))'
```

Safe fix: pass the intended file explicitly with `-config`, or set a non-blank
`WEATHERAPI_CONFIG`. Fix YAML syntax and compare the file with
[`examples/config.minimal.yml`](../examples/config.minimal.yml).

## Startup Fails with `config.databases requires at least one entry`

Symptom: the process exits before opening any database.

Likely cause: `databases` is missing or empty in the YAML file.

Diagnostic:

```sh
rg -n '^databases:' config.yml
```

Safe fix: add at least one database entry. The first entry is the primary
weather data store used for reads.

## Startup Fails with `open databases`

Symptom: the process exits while opening configured database handles.

Likely causes:

- PostgreSQL host or port is unreachable;
- credentials are invalid;
- the database name in `uri` is wrong;
- TLS/`sslmode` settings do not match the server;
- the configured driver is not usable for this deployment.

Diagnostic:

```sh
psql 'postgres://USER:PASSWORD@HOST:5432/DBNAME?sslmode=disable' -c 'select 1'
```

Safe fix: correct `uri`, `username`, `password`, network routing, firewall
rules, or TLS settings. Keep production secrets out of committed config files.

## Startup Fails with `select primary database`

Symptom: databases open, then the process exits selecting the primary database.

Likely cause: feedapi opened a registry that does not contain the first
configured database name.

Diagnostic: inspect the first `databases` item in the active config and verify
that `name` is present and non-empty.

Safe fix: give the first database entry a stable `name` and keep it as the
weather database entry.

## Startup Fails with `build app`

Symptom: the process exits after database setup but before serving HTTP.

Likely causes:

- feedapi cannot construct the HTTP app from the config;
- renderer or template setup failed;
- endpoint registration failed.

Diagnostic: read the error text after `build app:`. If the error mentions
templates, inspect `templates.base_dir`.

Safe fix: correct the config value mentioned by the error. For template errors,
make the directory readable and ensure the repository's `*.txt.tmpl` files are
present.

## Requests Return `400 invalid_parameter`

Symptom: JSON error body includes:

```json
{
  "error": {
    "code": "invalid_parameter",
    "message": "..."
  }
}
```

Likely causes:

- unknown query parameter;
- `precision` outside `0` through `2`, or not an integer;
- `precision` used on alerts, discussions, weather stories, or outlooks;
- `tz` used on observations, current conditions, or alerts;
- invalid timezone value;
- both `tz` and `TZ` are present with different values.

Diagnostic: compare the request against the route's query parameters in
[`docs/api.md`](api.md). Reproduce with `curl -i` to see the status and body.

Safe fix: remove unsupported parameters or correct values. Use `tz=Chicago`,
`tz=America/Chicago`, a supported US abbreviation, or an offset such as `TZ=-5`
on routes that accept timezone selection.

## Requests Return `406 unsupported_format`

Symptom: the response status is `406 Not Acceptable` and the error code is
`unsupported_format`.

Likely causes:

- `format` has a value other than `json`, `xml`, or `text`;
- the `Accept` header cannot be matched to a registered renderer;
- the configured default format is unsupported.

Diagnostic:

```sh
curl -i 'http://localhost:8080/observations?format=json'
curl -i -H 'Accept: application/json' 'http://localhost:8080/observations'
```

Safe fix: request `format=json`, `format=xml`, or `format=text`, or set
`server.default_format` to a supported value.

## Text Responses Fail or Do Not Render Expected Text

Symptom: `format=text` fails, returns an error, or does not contain expected
endpoint text.

Likely causes:

- `templates.base_dir` points to the wrong directory;
- templates were not copied into the runtime container or deployment directory;
- file permissions prevent reading templates;
- a customized template has invalid syntax.

Diagnostic:

```sh
find templates -maxdepth 1 -name '*.txt.tmpl' -print | sort
curl -i 'http://localhost:8080/forecast/hourly?format=text'
```

Safe fix: restore the repository's `templates/` directory or update
`templates.base_dir` to the mounted template path. In the Docker image, the
default template directory is `/weatherapi/templates`.

## Successful Response Has `data: null`

Symptom: the response is `200 OK`, but JSON contains `"data": null`.

Likely causes:

- weatherfeeder has not populated the relevant table yet;
- the relevant latest row does not exist after a database restore;
- the service is pointed at an empty or wrong database;
- current conditions have no observations in the implemented 30-minute window.

Diagnostic:

```sh
curl -s 'http://localhost:8080/observations?format=json'
curl -s 'http://localhost:8080/conditions/current?format=json'
```

Safe fix: verify weatherfeeder is running and writing to the same database that
`weatherapi` uses as its first configured database. For current conditions,
wait for recent observations or inspect weatherfeeder ingestion.

For convective outlooks, also verify that weatherfeeder has applied its
`weather.outlook.v2` table shape and is writing `outlook_runs`, `outlooks`, and
`outlook_discussions`.

## Forecast Day Routes Return Empty `periods`

Symptom: `/forecast/hourly/today`, `/forecast/hourly/tomorrow`,
`/forecast/narrative/today`, or `/forecast/narrative/tomorrow` returns a
forecast object with an empty `periods` array.

Likely causes:

- no period `startTime` falls on that calendar day in the selected timezone;
- the request omitted `tz`, so UTC day boundaries were used;
- the stored forecast is stale.

Diagnostic:

```sh
curl -s 'http://localhost:8080/forecast/hourly/today?tz=America/Chicago'
curl -s 'http://localhost:8080/forecast/hourly?tz=America/Chicago'
```

Safe fix: provide the intended `tz` value and verify the unfiltered forecast
contains periods for the expected local date.

## Timezone Errors

Symptom: requests with `tz` or `TZ` return `400 invalid_parameter`.

Likely causes:

- the timezone is not an IANA location, supported US abbreviation, supported
  alias, or valid UTC offset;
- an offset is outside `-14:00` through `+14:00`;
- both `tz` and `TZ` are present but do not match case-insensitively.

Diagnostic:

```sh
curl -i 'http://localhost:8080/forecast/hourly?tz=not-a-timezone'
curl -i 'http://localhost:8080/forecast/hourly?tz=CDT&TZ=EST'
```

Safe fix: use one timezone parameter. Known-good examples include
`tz=America/Chicago`, `tz=Chicago`, `tz=CDT`, and `TZ=-5`.

## Precision Errors

Symptom: requests with `precision` return `400 invalid_parameter`.

Likely causes:

- value is not an integer;
- value is less than `0` or greater than `2`;
- route does not accept `precision`.

Diagnostic:

```sh
curl -i 'http://localhost:8080/conditions/current?precision=3'
curl -i 'http://localhost:8080/alerts/active?precision=1'
```

Safe fix: use `precision=0`, `precision=1`, or `precision=2` only on
observations, current conditions, and forecast routes.

## Missing or Stale Weather Data

Symptom: responses are successful but older than expected, or endpoint families
are empty.

Likely causes:

- weatherfeeder is stopped or failing;
- weatherfeeder writes to a different database than `weatherapi` reads;
- a restore or deployment changed database credentials;
- upstream provider ingestion is delayed outside `weatherapi`.

Diagnostic: inspect weatherfeeder logs and query the configured Postgres
database directly for recent rows in the relevant weatherfeeder tables.

Safe fix: repair weatherfeeder ingestion or database routing. Restart
`weatherapi` only when config or database connectivity changed.

## Related Docs

- [`docs/api.md`](api.md): endpoint contract, query parameters, errors
- [`docs/config.md`](config.md): YAML fields and examples
- [`docs/operations.md`](operations.md): runtime and recovery boundaries
- [`docs/integrations/feedapi.md`](integrations/feedapi.md): config, rendering, and error-contract boundaries
- [`docs/integrations/weatherfeeder-postgres.md`](integrations/weatherfeeder-postgres.md): table and freshness assumptions
