---
title: "Troubleshooting"
description: "The failures people actually hit, and the first thing to check for each."
icon: "screwdriver-wrench"
---
## Connecting
Open that connection in **Settings** and press **Test**. It calls the endpoint the way
a client would and reports how many tools answered — compare it against
[the counts](/tools/overview#the-counts).
If the test passes and the client still shows nothing, the client is usually caching a
failed handshake: remove the server from its config, restart it, and add it again.
Use the bearer form instead. Drop the token from the path, point the URL at
`/api/mcp`, and send `Authorization: Bearer `. Both routes resolve to the same
connection. [The config →](/connect#a-client-that-insists-on-a-header)
Bridge it with `mcp-remote`. It needs Node and nothing else.
[The config →](/connect#a-client-that-only-speaks-stdio)
Three things end a connection: the token was **rotated**, the connection was
**deleted**, or the account was **suspended**. `list_connections` from another client
tells you which — and if you have no other client, the Connections tab shows the same
rows.
Admin tools are hidden from a member's tool list entirely, so a member should never see
one offered. If a tool is being *called* and refused, the client has a stale tool list
cached from an admin session — restart it.
## Resumes
Your host has no headless Chromium. Use **⋯ → Open print view** and your browser's
**Save as PDF** with margins set to **None** — the same document, one more step.
[Getting one-click export →](/self-hosting/pdf)
`update_resume` with `data` replaces the **whole** document. Something sent a partial
one. There is no undo.
Prevention: install the [`hired` skill](/skills), which carries the read-first rule, and
tailor into a `duplicate_resume` copy rather than editing an original.
Three things have to be true: a photo is set on your profile, `showPhoto` is on for
that document, and the template renders one. **Harvard never does**, whatever you set —
Classic, Modern, Compact and Editorial do.
Anything over 400KB is rejected. Downscale first — a resume prints the photo about an
inch square, and a 512px original is already more than that needs.
Unpublishing **destroys** the address rather than pausing it, and publishing the same
resume again mints a different one. The old URL cannot be recovered. Send the new link.
## The pipeline
It returns `captured: false` and creates nothing when the page does not state the
employer or the role readably — deliberately, because an employer guessed from a URL is
worse than one you were asked about. It hands back whatever it *did* parse; fill in the
rest and create the application by hand.
A company's logo comes from its `website`, and only from its own domain — a Greenhouse
or Ashby link is the job board rather than the employer. `list_companies` is the fast
way to spot companies with no website on file.
If **no** logos show anywhere, an admin has turned them off instance-wide.
The reason an application ended is not an input. `diagnose_search` reads how far each
one ever got — its stage history and `interviewRound` — plus how many you send a week,
how long each stage takes and which resume gets answered; a round nobody numbered
counts as the first one, so deep interviews left unnumbered read as shallow ones.
Reasons are what the funnel reads: `get_funnel` splits each rung's endings by their
LOSS tag, so "Ghosted" and "Rejected" separate there rather than in the advice, and a
`LOST` with no reason on it tells the funnel only that it stopped.
`update_company` replaces the `notes` field. Something wrote new notes without reading
the old ones first. There is no undo — the [`research_company`](/workflows#research-a-company-into-the-crm)
workflow exists specifically to make the read-first step explicit.
## The instance
`admin_health` first — database, migrations, email, billing, assistant activity, error
count. Then `admin_recent_errors` for the specifics behind an error count.
[Health and errors →](/administration/health)
`admin_list_invites` is where an unaccepted invitation lives: it carries `emailSent`,
the exact `emailError` when the send failed, and the link to send by hand. Nobody has
an account until they accept, so `admin_user_detail` has nothing to look up yet — that
one is for somebody already in. [Email →](/self-hosting/email)
You get Resend's exact reason back, and it is almost always an unverified sending
domain. Verify the domain first, then make the from address one on it.
Almost always `DATABASE_URL` — missing, or pointing at a database that is not up yet.
On Railway that shows as a crash-and-retry loop until the Postgres service exists and
the reference is set.
A billing check that reads **down** usually means the signing secret is wrong; one that
says Stripe has never called means the webhook endpoint was never added on Stripe's
side. `admin_sync_billing` reconciles a missed webhook.
[Billing →](/self-hosting/billing)
Set `RESET_OWNER_PASSWORD=1` on the app service and restart. A fresh owner password is
printed to the logs. Remove the variable afterwards, or it resets on every boot.
Check the migration line in `admin_health`. A half-applied migration is invisible until
somebody hits the screen that needs it. `npm start`, the Docker image and the Railway
start command all run `prisma migrate deploy` first — `npm run dev` does not.