---
summary: Common symptoms and what they usually mean.
title: Troubleshooting
path: troubleshooting
status: published
---

A short list of things that go wrong and how to fix them. If none of these match, check the request id in the response envelope and grep the ScaiGrid logs for `persona_` log events.

## Publishing returns `PERSONA_MODEL_NOT_FOUND`

The `model_slug` on the persona doesn't resolve to a frontend model in the catalogue. Either you mistyped the slug, the underlying model was deleted, or the model exists but isn't visible to your tenant.

- Check `/v1/models` and verify the exact slug.
- If the model was unintentionally deleted, restore or recreate it. The persona row stays valid until you fix this.

## Caller gets `model not found` invoking a published persona

The published model's slug is `tenant/{tenant_slug}/{persona_slug}`, not the persona's own slug. Inspect the persona's `published_model_id` to find the frontend model, then look up its slug.

Common mistakes:

- Using the bare `slug` ("acme-support") instead of the tenant-qualified slug.
- Wrong tenant slug — the tenant's slug, not the tenant id.
- Persona was unpublished while the caller was caching the slug.

## Persona answers from system prompt, ignores attached sources

Retrieval ran but returned nothing useful. Causes:

- **RAG disabled.** Check `rag_enabled` is `true` on the persona.
- **No active sources.** Listed sources may have `status: "disabled"`. List them and re-enable.
- **Collection access denied.** If your collection is ACL'd, the invoking caller may not have read access. The enricher silently drops chunks the caller can't see. Test as a user who has the access.
- **`rag_min_score` too high.** Drop it (try 0.3 — 0.4) to let weaker matches through.
- **Wrong collection id.** A typo on the source — the enricher logs `persona_rag_collection_search_error` if the collection lookup fails. Verify by listing sources on the persona.

## Persona confabulates

Says confident things that aren't in the source corpus.

- The persona's `system_prompt` should explicitly tell the model to answer only from context. The default behaviour is permissive.
- Tighten `rag_min_score`. With weak chunks gone, the model has fewer false anchors to confabulate from.
- Drop `rag_top_k` if you're injecting too much marginally-relevant context.
- Move from `single_step` to `multi_step` — the LLM-refined query often surfaces better chunks.

## ScaiDrive shares list returns 503 or 502

- **503 `SCAIDRIVE_NOT_CONFIGURED`** — the module doesn't have a `scaidrive_base_url` set in module config. Set it via the modules admin API.
- **502 `SCAIDRIVE_TOKEN_EXCHANGE_FAILED`** — the caller's token can't be exchanged. Most common cause: API keys without ScaiDrive scope. Retry with a JWT-authed caller.

## ScaiDrive source returns no chunks at invocation time, even though `/scaidrive/shares` listed the share

Token exchange succeeded for the listing call but failed at retrieval time, or ScaiDrive itself rejected the search.

- Check logs for `persona_rag_token_exchange_error` (exchange failed mid-invocation) or `scaidrive_search_error` (search call failed).
- If the calling identity changed between listing and invocation (e.g. shared API key vs end-user JWT), the access set differs — that's expected.

## Publishing assigns to no groups even though `group_ids` was passed

Group-scope validation rejected the assignments. The check is silent — group ids outside the caller's scope are dropped.

- A super-admin can target any group.
- A partner-admin can target partner-scoped groups for their partner only.
- A tenant-admin can target tenant-scoped groups for their tenant only.
- Global groups (`scope_type: "global"`) are super-admin-only.

Verify by listing memberships on the group after publish: if the persona's frontend model slug isn't there, scope rejection is the reason.

## Avatar upload returns `STORAGE_ERROR`

The S3 / Garage put failed. Causes:

- Bucket credentials misconfigured in module settings.
- Bucket region mismatch.
- Bucket disk full or quota exceeded.

The persona's `avatar_url` is not updated on failure — retry after fixing the underlying storage issue.

## Persona slug collides

`PERSONA_SLUG_CONFLICT` on create — another persona in the same tenant already uses this slug. Either reuse the existing persona or pick a different slug. Slugs are tenant-scoped, so the same slug can exist in another tenant.

## Updates don't appear in invocations

If `PUT /personas/{id}` returns success but live invocations still see the old behaviour:

- Verify the persona is actually published — `published: true` in the GET response.
- The frontend model is synced on save, but routing caches may need a few seconds. If it persists, restart the inference workers or rebuild the model cache.
- `system_prompt` is propagated via `system_prompt_template` on the frontend model — the underlying model dispatch must honour template injection. Vendor backends that ignore system prompts (rare) won't reflect the change.

## Persona invocations not metered against the right cost centre

Accounting attributes usage to the **frontend model** that was called. For a published persona, that's the persona's frontend model — not the underlying vendor model. If you're grouping by vendor model and a persona's usage looks "missing", group by frontend model slug or filter for slugs prefixed with `tenant/`.
