Install problems
pip install persona-agent-sdk fails or resolves an old version
The package is published under persona-agent-sdk (the name personaai was already too close to an
unrelated existing PyPI project) but imported as personaai. Verify you installed the right name,
and that the version is current:
httpx>=0.27.
I can import the SDK from the repo but not after installing
If you’re working from a local checkout, either install it (pip install -e /path/to/agent-marketplace/sdk/python)
or run from the repo’s sdk/python directory so src/personaai is importable. A bare pip install persona-agent-sdk
never installs your local checkout — you’ll get the published package.
Authentication problems
PersonaAuthError (401/403) on every call
401: the credential is invalid, malformed, expired, or revoked. Re-mint it in Developer Studio. Confirm the shape is"<keyId>.<secret>"— a truncated or copy-paste-corrupted value fails exactly this way.403: the Project isn’tACTIVE(suspended), or the asserted identity can’t act. Check Project status in Developer Studio.- Make sure the credential isn’t wrapped in quotes/whitespace from an env file (
export PERSONA_CREDENTIAL="<keyId>.<secret>"in a.envfile usually comes through fine, but watch for trailing characters).
ValueError: TransportConfig: "credential" is required
You passed an empty/missing credential at construction — validation is synchronous and happens
before any network call. Check that os.environ["PERSONA_CREDENTIAL"] actually resolved.
PersonaValidationError with EXTERNAL_USER_REQUIRED on Threads/Files/Chat
Those resources require a runtime-plane client. Construct the client with external_user_id set:
Empty or missing results
providers.list() / audit_logs.list() returns [] even though I created Providers
You’re on a runtime-plane client (constructed with external_user_id). Providers and audit
logs have no ExternalUser ownership concept, so the server short-circuits these calls to an empty
result (existence-hiding — deliberately silent, not an error). Use a control-plane client (no
external_user_id) for Providers and audit logs. See
Providers and
Audit logs.
agents.get() doesn’t return systemPrompt/providerId
The Agent isn’t owned by the calling identity (e.g. a public Agent belonging to someone else) — the
backend strips both fields in that case by design. The Agent still runs; you just can’t read its
prompt or provider wiring.
threads.list() items don’t have a string agentId
Thread["agentId"] is a populated object ({_id, name, avatar, slug}) on list(), but a bare
id string on create()/get(). Check which call produced the value before assuming a shape.
Skill["isOwner"] is missing
isOwner is only present on the result of skills.get(), not list()/create()/update().
Chat problems
Chat raises PersonaApiError 404 when passing thread_id
thread_id must belong to the asserted external user and the agent_id you’re calling with.
Passing someone else’s Thread, a different Agent’s Thread, or a nonexistent id 404s — it does not
silently fall back to a different conversation. Create the Thread with
user_persona.threads.create({"agentId": agent_id}) and pass that _id.
send_message() returns text but no stream events
That’s expected with send_message() — it drains the stream and returns {"text", "interrupt", "events"}. If you need per-delta control (streaming to a UI as it arrives), use chat.stream()
directly and switch on event["type"] == EventType.TEXT_MESSAGE_CHUNK.
My interrupt never finishes; the run keeps pausing
Resume on the next call withmessages=[] (no new user message — you’re answering the
interrupt, not starting a new turn), thread_id set to the same Thread, and a resume shape
matching the interrupt’s kind:
kind == "hitl"→resume={"decisions": [{"action": ..., "decision": "approve" | "reject"}]}kind == "clarification"→resume={"answers": [...], "text": ...}
The stream hangs or produces no output
No default timeout is configured by the SDK — if your app needs one, wrap the call inasyncio.wait_for(...) (async) or pass an http_client= with timeout= set. If you never see
TEXT_MESSAGE_CHUNK events, check that the Agent has isActive and a working Provider
(providers.test_connection()).
File problems
files.download() doesn’t return parsed JSON
Correct — download() returns the raw httpx.Response (the only method in the SDK that does).
Read .content/.text/.iter_bytes() (async: .aiter_bytes()). JSON parsing isn’t involved;
that’s the point of a raw file stream.
Upload fails with PersonaValidationError
Check the payload: filename and content are required; content must be bytes or a binary
file object; pass contentType when it can’t be inferred (e.g. "application/pdf"). Knowledge
uploads are limited to 10 files × 20MB of PDF/TXT/MD/JSON/CSV per call.
General problems
Every request raises PersonaApiError with code == "NON_JSON_ERROR_RESPONSE"
The failure response had no JSON body — usually a proxy/load-balancer error page (502/503/504 HTML)
rather than an API error. Check your network path, base URL, and any reverse proxy. The status code
is still on the exception (err.status_code).
I’m getting 429s and the call still fails
The SDK retries 429s up tomax_retries (default 2), honoring Retry-After. If you’re still
failing, raise max_retries, spread out requests, or back off after the final failure. Only 429 is
retried — everything else raises on the first attempt.
bulk_delete() doesn’t raise even though some ids failed
That’s the contract — bulk_delete() is best-effort. Check the returned BulkDeleteResult:
404s that shouldn’t happen (I just created it)
Two common causes:- Wrong id shape — you passed
provider["id"]to an_id-shaped resource or vice versa (see _id vs id). Providers/Files useid; Agents/Skills/ Knowledge/Threads/MCPs use_id. - Ownership mismatch — you created the resource with one identity and are now reading it with another (e.g. created via control-plane client, read via a runtime-plane client asserting a different user). Resources are scoped to their owner.
Getting started with the wrong client for the job
- Control-plane (no
external_user_id): Providers, audit logs, and provisioning/administration CRUD. - Runtime-plane (with
external_user_id): Threads, Files, Chat, and per-userscope: "mine"listings.