131 lines
4.9 KiB
Markdown
131 lines
4.9 KiB
Markdown
# Troubleshooting
|
||
|
||
## Application will not start
|
||
|
||
### `Could not resolve placeholder 'X'`
|
||
|
||
```
|
||
java.lang.IllegalArgumentException: Could not resolve placeholder 'OPENAI_API_KEY' in value "${OPENAI_API_KEY}"
|
||
```
|
||
|
||
A required environment variable is missing. This is the intended behaviour — the
|
||
service refuses to start rather than run with an unusable credential.
|
||
|
||
**Fix:** set the named variable. Locally that means `.env`; in production,
|
||
`.env.production` on the deployment host followed by
|
||
`docker compose restart parser-service`. [`.env.example`](../.env.example) lists every
|
||
variable and marks which are required.
|
||
|
||
Check what the container actually received:
|
||
|
||
```bash
|
||
docker compose exec parser-service env | grep -E 'MONGODB|OPENAI|MINIO|JWT'
|
||
```
|
||
|
||
### MongoDB connection refused / timeout
|
||
|
||
The service cannot operate without MongoDB, so this is fatal at startup.
|
||
|
||
```bash
|
||
./scripts/smoke-mongodb.sh # reachability + configured connection string
|
||
```
|
||
|
||
Work through, in order:
|
||
|
||
1. **Reachability** — `nc -z $MONGODB_HOST $MONGODB_PORT`. If this fails the problem is
|
||
network or firewall, not credentials.
|
||
2. **Credentials** — `MONGODB_USERNAME` / `MONGODB_PASSWORD` are set and exported.
|
||
3. **Auth database** — `MONGODB_AUTH_DATABASE` must match how the user was created,
|
||
normally `admin`. A user created against `admin` but authenticated against
|
||
`parser_db` fails with an authentication error, not a connection error.
|
||
4. **Grants** — the user needs read/write on `MONGODB_DATABASE`.
|
||
|
||
Timeouts are 30s for connect, socket and server selection. A slow first request after
|
||
an idle period is usually server selection re-establishing the topology.
|
||
|
||
Historical detail: [archive/setup-notes/MONGODB_TROUBLESHOOTING.md](archive/setup-notes/MONGODB_TROUBLESHOOTING.md).
|
||
|
||
## Runtime failures
|
||
|
||
### `401 Unauthorized` from OpenAI
|
||
|
||
```
|
||
OpenAI request failed: 401 Unauthorized from POST https://api.openai.com/v1/chat/completions
|
||
```
|
||
|
||
The key in `OPENAI_API_KEY` is invalid, revoked, or belongs to an organisation without
|
||
access to the configured model.
|
||
|
||
```bash
|
||
./scripts/smoke-openai-api.sh # validates the key directly against the API
|
||
```
|
||
|
||
Then check the service's own view: `GET /api/openai/test`.
|
||
|
||
If the key is fine but calls still fail, confirm `openai.model.name` (`gpt-4o-mini`) and
|
||
`openai.model.name.text` (`gpt-4o`) are both available to your account.
|
||
|
||
### `401` from this service's own endpoints
|
||
|
||
That is JWT validation, not OpenAI. `security.jwt.secret-base64` must be **byte-identical
|
||
to the secret used by the auth service that issued the token**. A mismatch produces a
|
||
signature failure on every request. Also confirm the header is `Authorization: Bearer <token>`
|
||
and the token has not expired.
|
||
|
||
### Rate limiting / slow AI responses
|
||
|
||
OpenAI calls retry with exponential backoff — up to 3 attempts normally, and up to 10
|
||
with a 5s–300s backoff specifically for rate-limit responses. Concurrency is capped at
|
||
3 requests. Sustained `429`s mean the cap is not low enough for your quota; lower
|
||
`openai.rateLimit.maxConcurrentRequests`.
|
||
|
||
Ollama timeouts are deliberately long (up to 5 hours) because it generates long-form
|
||
report text on self-hosted hardware. A request that appears hung may simply be
|
||
generating.
|
||
|
||
### Image or video generation returns null
|
||
|
||
```
|
||
[Imagen3] Credentials file not found: keys/google-key.json
|
||
```
|
||
|
||
The Google service-account key is missing from the build. It must exist at
|
||
`src/main/resources/keys/google-key.json` **when the jar is built**, because it is
|
||
loaded from the classpath. See
|
||
[configuration.md](configuration.md#the-google-service-account-key).
|
||
|
||
This degrades gracefully — only image and video generation are affected.
|
||
|
||
### Reports fail with a date `NullPointerException`
|
||
|
||
```
|
||
Cannot invoke "java.time.LocalDateTime.toLocalDate()" because "end" is null
|
||
```
|
||
|
||
`ReportGenerationService` defaults a missing range to the last 30 days. If you see this
|
||
again, a new code path is formatting `startDate`/`endDate` without a null check.
|
||
Background: [archive/changelogs/NULL_POINTER_FIX.md](archive/changelogs/NULL_POINTER_FIX.md).
|
||
|
||
### CORS errors in the browser
|
||
|
||
Origins come from `CORS_ALLOWED_ORIGINS` and default to `https://konturai.kz` and
|
||
`https://www.konturai.kz`. A local frontend needs its origin added explicitly —
|
||
`cors.allow-credentials=true` means a wildcard origin is not permitted.
|
||
|
||
## Diagnostics
|
||
|
||
```bash
|
||
curl -fsS localhost:8080/api/parser/health # liveness
|
||
docker compose logs -f parser-service # follow logs
|
||
docker compose logs --tail=200 parser-service | grep -i error
|
||
```
|
||
|
||
Raise log detail for a specific area by overriding its level, e.g.
|
||
`logging.level.kz.konturai.parser.service.MarketingAnalysisService=DEBUG`.
|
||
|
||
`MarketingController` and `MarketingAnalysisService` already log at `DEBUG`. Mongo
|
||
driver logs are at `WARN` to keep the noise down — raise
|
||
`logging.level.org.springframework.data.mongodb` to `DEBUG` when investigating queries.
|
||
|
||
Heap dumps from OOM kills land in `/dumps/heap.hprof` inside the container.
|