Troubleshooting
Find the cause and the fix for common staqly errors, from startup failures to webhook and sign-in problems.
Look up the error or symptom you see below; each entry says what it means and how to fix it.
Where the fix differs, it covers both the binary (staqly serve) and the Docker image. If your
problem isn't here, check the logs for the request's request_id.
Common problems
Every request to the Community Edition needs its access token, also from this computer.
- No token sent ("local mode needs the access token"): send
Authorization: Bearer {ACCESS_TOKEN}. Print the token withstaqly serve token(binary) ordocker exec staqly server token(Docker), and give it to agents and scripts asSTAQLY_API_KEY(export STAQLY_API_KEY=$(staqly serve token)). - Wrong token ("invalid access token"): the token was rotated, or the agent has the token of another install. Print the current one and update the agent's configuration.
- Lost the token: it is never lost while the data is there;
tokenprints it again from the data folder (access_token). If you think someone else has it, runtoken --rotate: the old one stops working at once and every browser is signed out. - The
staqlyCLI on the same computer asstaqly servereads the token by itself; against Docker give itSTAQLY_API_KEYorstaqly login --key "$(docker exec staqly server token)". docker exec -i staqly mcp-stdioneeds no token.
Invalid settings stop staqly serve or the staqly container instead of falling back silently: STAQLY_MODE must be
local or cloud; STAQLY_LOCAL_TOKEN, when set, must start with stk_local_ (at least 32 characters);
NOTIFY_SECRET_KEY must be at least 32 bytes (openssl rand -hex 32), STAQLY_SECRET_KEY 32 bytes base64 (openssl rand -base64 32); LOG_LEVEL must be
debug, info, warn or error and LOG_FORMAT json or text.
More of the same kind:
- On/off settings (
COOKIE_SECURE,TRUST_PROXY,WEBHOOK_ALLOW_PRIVATE,S3_FORCE_PATH_STYLE...) taketrueorfalse(also1/0);yesoronis refused. - Counts (
JOB_CONCURRENCY,MAX_UPLOAD_MB,NOTIFY_*,RATE_LIMIT_*) must be whole numbers above 0; durations (SESSION_TTL,WEBHOOK_RETRY_BASE,NOTIFY_RETRY_BASE...) Go durations such as90s,15mor720h(PROCESSING_TIMEOUTalso takes0). STORAGE_DRIVERisdiskors3;s3names theS3_*settings it misses.- The Community Edition refuses
DATABASE_URL: it keeps its data in SQLite (DATABASE_PATH).
The settings listed in Configuration say what each one takes.
A listing ran longer than 5 seconds. Add filters (collection, status, channel, dates). See Pagination & search.
The expected_version you sent is older than the post's version: someone (a person in the
dashboard, another agent) edited it meanwhile. Reload the post and apply your change again.
- Soon on an OAuth platform such as X, or
app_not_configured: the server has no developer app for it. Register one with the platform and put its keys in the server's environment (PROVIDER_X_CLIENT_ID,PROVIDER_X_CLIENT_SECRETin.env), then restart (Developer apps). provider_soon: the platform is in the catalog but not available in this build yet.provider_disabled, or the platform is missing from Add channel: it is turned off withPROVIDER_<ID>_ENABLED=false. Posts already scheduled on its channels still go out; new ones are refused.
A publish, a test or a token refresh failed with the stored credentials; the row shows the
platform's error. Reconnect in the row's menu: OAuth platforms go through the platform again,
token platforms take fresh credentials. Targets on the channel fail until then. If the error says
the stored credentials cannot be read, secret.key (or STAQLY_SECRET_KEY) changed: restore the
old key from your backup, or reconnect every channel.
A target on your own automation waits for a reported result; the post shows how long it has
waited of the collection's limit. Check that your webhook receiver got post.publish_requested
(Webhooks → deliveries) or poll GET /v1/work, then report with
POST /v1/posts/{id}/targets/{channel}/result. Nothing reported within the limit fails the
target with No result reported in time. For a platform channel, look at Settings → System →
Queue for a failed job and its error.
Changing where an alert sends requires re-entering its secret in the same request. See Alerts.
Webhook and alert subscriptions must name events staqly knows: *, a family glob such as
post.*, or an event type from Events. A typo like post.publised or posts.*,
or a custom event such as post.shipped, is refused instead of never matching.
The error lists the valid event types of that family (or the families), so you can pick the right one.
Test sends are limited per API key or session: a burst of 5, then 10 per minute.
Every browser signs in once. Open the link staqly printed at start
(http://localhost:8080/#token=...), or paste the token: staqly serve token (binary) or
docker exec staqly server token (Docker) prints it. After a token --rotate every browser signs
in again with the new token. Phones sign in with Connect a device in a signed-in dashboard, or a
one-time link from staqly serve connect-link / docker exec staqly server connect-link (5 minutes,
single use).
The phone must reach your computer's LAN address. Binary: start with staqly serve --expose
(without it the dashboard only listens on 127.0.0.1); the QR code then uses your Wi-Fi address.
Docker: type your computer's Wi-Fi address in the Connect a device dialog, or set
-e PUBLIC_DASHBOARD_URL=http://192.168.1.23:8080 (see Run with Docker).
In both cases the phone must be on the same network and port 8080 must not be blocked by a firewall.
See Phones & tablets.
Signing in to app.staqly.ai (email codes, passkeys, 403 sign_in_with_account) is covered in
Accounts → When sign-in fails; a 402 plan_limit_exceeded names the
limit in error.details.limit (see Plans & limits and Settings → Plan & usage).
You are sending a session cookie. Scripts should use Authorization: Bearer stk_... (no
CSRF needed).
On Staqly Cloud, the API key lacks a scope. Create a key with the right scopes under Integrations → API keys. Keep admin off agent keys. A key never does more than its creator's current role, so a demoted creator narrows their keys too.
Adjust WEBHOOK_ALLOW_PRIVATE / WEBHOOK_ALLOW_LOOPBACK. WEBHOOK_ALLOW_PRIVATE defaults to
true in the Community Edition. With the binary, a receiver on the
same computer (localhost) needs WEBHOOK_ALLOW_LOOPBACK=true. Inside Docker, localhost is
the staqly container itself — use host.docker.internal or a container name on a shared Docker network (see
n8n networking).
Make n8n listen on all interfaces (or the Docker bridge) and use
http://host.docker.internal:5678/webhook/staqly. On Linux the container needs
--add-host host.docker.internal:host-gateway in docker run (compose.yml sets it).
Set NODE_FUNCTION_ALLOW_BUILTIN=crypto on n8n (the example integrations/n8n/compose.yml
does). The demo workflow needs it: its Verify & parse node fails closed and rejects every
event until the secret is set.
STDIO runs inside the staqly container; with the binary, connect agents over HTTP
(http://localhost:3333/mcp) instead. Don't pass -t to docker exec. Run docker exec -i staqly mcp-stdio by hand —
errors go to stderr.
Another program (or a second staqly) uses port 3333 or 8080. Binary: start with other ports,
e.g. staqly serve --port 4333 --dashboard-port 9090. Docker: recreate the container with other
host ports (-p 127.0.0.1:4333:3333 -p 9090:8080 -e PUBLIC_API_URL=http://localhost:4333 -e DASHBOARD_PORT=9090,
see Other ports). In both cases update your MCP client
URLs. Don't run the binary and the Docker setup at the same time on the default ports.
Only pictures (PNG, JPEG, GIF, WebP, AVIF), videos (MP4, WebM, MOV) and audio (MP3, WAV, OGG, M4A)
are accepted; documents and archives are not media, and SVG and HTML are refused because they can
carry script. Raise the size limit with
MAX_UPLOAD_MB.
Shouldn't happen with the bundled configuration (immediate transactions and a 10 s busy
timeout). Make sure only one staqly server (staqly serve or the server process) uses a
data directory.
Check the logs
staqly serve # logs appear in this terminal
staqly service logs -f # when it runs in the background (staqly service install)Text with the binary, JSON lines with Docker (change with LOG_FORMAT; LOG_LEVEL=debug for more); request
paths are logged, headers and query strings are not. Find everything about one failed request
by the request_id (or trace_id) from the error body — see
Logs & tracing.