Ostler
GitHub

Docs Help

Troubleshooting Ostler

Symptoms, causes and fixes for Ostler. Start with ostler doctor.

On this page

Start with ostler doctor. It launches Chrome, round-trips a page and, if memory is on, prints a memory report and checks Qdrant. The report says in plain words what is stored where and what leaves the machine:

Memory: on, Qdrant at https://… (tenant "default")
  sealing:    ON … (or OFF, with a warning)
  key:        <path to memory.key> (owner-only, good)   | from OSTLER_MEMORY_KEY | not created yet
  embeddings: cloud | local (ollama at …) | local dev-hash
  isolation:  shared collections | one set of collections per tenant
  transport:  https (encrypted) | http to this machine | http to a remote host: REFUSED / ALLOWED
  qdrant:     reachable, collections ready. OK

With nothing configured it prints Memory: in-process, this session only and the rest still works. It never creates the sealing key. Every failing check prints a fix: line with a concrete command. ostler doctor --fix applies only the safe ones: it creates the config directory and tightens an over-open key file to owner-only. It never creates keys, installs software, edits client configs or touches the network. ostler doctor --cdp-url http://127.0.0.1:9222 also tests attaching to a Chrome you started yourself.

symptomlikely causefix
serve --cdp-url says it could not read /json/versionno Chrome is listening on that port, or it was started without a dedicated --user-data-dir (Chrome ignores the debug flag on its default profile)start it as in CLIENTS.md, then ostler doctor --cdp-url ...
--cdp-url ... refusing a non-loopback hostthe URL points off this machineuse 127.0.0.1; for a remote browser tunnel the port with SSH
ostler install says the file is not valid JSON/TOMLthe client's config has a typo or commentsnothing was written; fix the file, or add the snippet from ostler setup <client> by hand
Client says it can't start ostler / command not foundthe client has a different PATH than your shelluse ostler setup <client>, which writes the binary's absolute path
Chrome: could not find Chrome or Chromiumnone on the usual pathsinstall one (the message has the command for your OS), or set OSTLER_CHROME=/path/to/chrome
the Chrome path "…" does not existOSTLER_CHROME or --chrome-path points at a missing filefix the path, or unset it to auto-detect (a wrong explicit path is an error on purpose, never silently replaced)
Launch fails with "exited before DevTools was ready" on Linux/Dockerrunning as root, or no sandbox supportset OSTLER_NO_SANDBOX=1; in containers also give Chrome a larger /dev/shm (--shm-size=1g)
The first call after Chrome crashed reports a restartthe server relaunches Chrome and tells the agent; open tabs and page state are lostre-navigate and continue; if it keeps failing, restart the MCP server (in Claude Code: /mcp, reconnect)
Server prints nothing and the agent sees no toolsstdout must carry only MCP messages; something else wrote to it, or the client expects another transportrun ostler serve in a terminal: it should print one ready line on stderr and wait
form_fill says UNMATCHED keyno field label/name matches that keycall form_inspect, then pass the exact label or the eNN ref
ambiguous in a fill reportseveral fields match equally welluse the ref (e12) from form_inspect instead of a label
NOT ACCEPTED with the page's messagethe page rejected the valuesfix the named fields and call form_submit again
sealing: OFF. warning: anyone who can read your Qdrant ...--seal off (or seal = off in the config)ostler config set seal on, then ostler memory seal to protect facts saved earlier (learned skills and episodes from before are dropped and relearned)
warning: other users on this machine can read the keymemory.key is not owner-onlychmod 600 on the path doctor prints
the sealing key is unreadable or malformed, or sealed memory returns nothingmemory.key / OSTLER_MEMORY_KEY is missing, damaged or a different key than the one that sealed itrestore your backup to the path doctor names. There is no recovery without the key: delete the key file and run ostler memory wipe --yes to start over. Points that fail to open are skipped, never returned
refusing to create a new memory keyno key exists yet and Qdrant could not be checked (or holds sealed memory this machine has no key for)start Qdrant and retry; restore a backup with ostler memory key import; for a genuine first-time setup with Qdrant down pass --allow-new-key. If sealed memory is there and the key is gone, ostler memory wipe --yes starts over
retired sealed format v1 or older key normalisationsealed points from an early build, or keys saved before norm() changedostler memory seal --tenant T (the key is right; this brings the data up to date)
refusing plain http / transport: http to a remote host: REFUSEDthe Qdrant URL is plain http:// to a non-loopback host, so the API key and any unsealed data would cross the network in clear textuse an https:// URL; if a VPN or SSH tunnel protects the link, pass --allow-insecure-qdrant (ostler config set allow_insecure_qdrant true)
warning: Cloud Inference only exists on Qdrant Cloud, and this URL is not one--embeddings cloud (the default) with a self-hosted URL--embeddings ollama (semantic, local) or dev-hash (local, not semantic)
cannot reach the local embedder / embedding model not found--embeddings ollama but Ollama is not running, or the model is not pulledollama serve, ollama pull all-minilm (the Ollama default), or ostler config set embedding_model <name> and embedding_dim to match
warning: model "…/…" looks like a Qdrant Cloud model namean Ollama setup still carrying the Cloud default modelostler config set embedding_model all-minilm
Qdrant rejected the API key (401/403) with --isolation collectiona scoped token only covers its own tenant's collectionsuse the token from ostler memory token for the same --tenant; Qdrant must run with service.jwt_rbac: true and an admin must have created the collections first (ostler memory list as admin does it)
this collection was created with a different embedding modelthe collection's vector size does not match --embedding-model / --embedding-dimuse the same model as before, or a different tenant or cluster
SERVER ERROR: the site answered with an HTTP error from form_submitthe submit got a 4xx/5xx and the page showed no validation messagesthe data may or may not have been stored: do not retry blindly; check with snapshot or ask the user
2 forms on this page and none was filled: pass form (...)form_submit with several forms and no form or control, and no earlier form_fill on this pagepass the form ref from form_inspect, or a submit control ref
qdrant: FAILED in doctorwrong QDRANT_URL/key, or Cloud Inference not enabled on the clusterdoctor prints a specific fix (unreachable, rejected key, or embedding-size mismatch). Check the URL includes the port (:6333), enable Inference in the Qdrant Cloud console, or use --embeddings ollama (local, semantic) or --embeddings dev-hash (not semantic) against open-source Qdrant. Memory is optional: unset QDRANT_URL to run without it
A tool result starts with Note: memory is unavailable (...)Qdrant failed twice in a row (down, slow past the 4 s request limit, or returning 5xx); lookups are skipped for 30 s, then one request retriesthe form tools keep working: pass values in the request. Fix Qdrant (ostler doctor), no restart needed
... is a cloud metadata address (always blocked ...)the agent tried 169.254.169.254, fe80::/10 or metadata.google.internalintended. If you really need it, add it to --allow-domain
A submit comes back as Nothing changed on a page that stays putthe site posts in the background and says nothing visible afterwards, so Ostler cannot tell it workedcheck with snapshot; do not resubmit blindly (it may have gone through)
npx -y ostler … is slow the first time, or fails offlinethe launcher downloads the binary once (cached in ~/.cache/ostler)run npx -y ostler doctor once while online; or install the binary with pip install ostler-mcp / install.sh and point your client at it (the npm package is not published yet)
checksum mismatch … Not installingthe download was corrupted or alterednothing was installed or run. Retry; if it persists, install from source and open an issue
Agent context fills uptoo many tools or large snapshots--tools forms, --lean, and ask for form_inspect instead of full snapshot
A tool result starts with CHALLENGE:a CAPTCHA or "verify you are human" page is blockingOstler never solves or evades these. Run with --headed, complete it in the window, then the agent calls wait_for_human. A persistent --profile-dir with a logged-in session triggers fewer challenges
browser exited before DevTools was ready (is another Ostler or Chrome already using profile …)Chrome allows one process per profile and two servers (two agent windows, subagents) share one --profile-dirgive each server its own --profile-dir, or omit it (throwaway profile per server; any number can run at once)
Google, DuckDuckGo or Bing return a wall or no resultssearch engines challenge headless browsers; Ostler is built for forms and does not evade theseuse your agent's own search tool for search and Ostler for the target site. If you must search through Ostler, run one --headed server with its own --profile-dir and solve the check yourself
A site blocks the browser or shows a CAPTCHAautomation detectionOstler does not evade it; see Searching the web
Rebuilt ostler but the agent still behaves as beforethe client keeps the old server processreconnect the MCP client (Claude Code: /mcp; others: restart it)

When not to use Ostler#

Ostler is a form-filling browser for an agent working on your behalf, on one machine. It is the wrong tool when:

  • The site walls off automation. CAPTCHA, Cloudflare/Turnstile, "verify you are human" pages and search-engine bot checks are reported with a CHALLENGE: line and handed to a person. Ostler never solves or bypasses them, and it is not built to avoid detection: there is no stealth patching, fingerprint spoofing, residential proxy or IP rotation. A site that blocks headless or datacenter Chrome will block Ostler. --headed plus a persistent --profile-dir lets you pass a check once; it does not make a bot wall go away.
  • You need scale. Each server drives one local Chrome (tabs share its cookies and profile). It is not a remote or cloud browser farm, not a crawler, and not meant for bulk scraping or high-volume account creation. More sessions means more servers, each with its own profile and its own memory use (see Benchmarks).
  • The flow needs an identity Ostler does not have. There is no mailbox, phone number, SMS/OTP receiver or authenticator: one-time codes, email-link verification, passkeys, hardware keys and 2FA prompts need a person. Passwords and card numbers are never read back or remembered; sensitive fields are refused and the agent is told to ask you. It does not create accounts on your behalf out of thin air.
  • The page is outside what the injected runtime can see. Cross-origin iframes (many hosted card fields), closed shadow roots, canvas-drawn UIs, native OS dialogs and file pickers, and desktop apps are not reachable. A control that stays disabled until a person scrolls or hovers is reported as disabled rather than worked around.
  • A wrong submit is expensive and nobody is checking. Ostler verifies every value by reading it back and refuses to call a submit a success without evidence, but it cannot know whether a form means what it says. For payments, legal acceptance and anything irreversible, run with --require-confirm-submit and review the result yourself.

When Ostler cannot finish, it says which field and why (rejected value with the page's own message, hidden or disabled control, key not found) and points at screenshot for the element; it does not report a partial fill as done.

Searching the web#

Ostler drives a real Chrome, but from a fresh, headless session many sites treat it as a bot. What to expect (it varies by network and over time):

  • Google, DuckDuckGo, Brave, Startpage, Reddit, news sites such as the NYT: often a bot wall or CAPTCHA. Ostler reports it and hands off to a person; it never tries to solve or get around it.
  • Bing: usually loads (but it may ignore first= / "Page 2" and serve page 1 again to a headless session), but may return results unrelated to your query ("Some results have been removed"). When a search-results URL's visible text matches fewer than about half of the query's words, navigate adds Warning: results do not seem to match the query "...". Treat the results as unreliable and try another engine or --headed.

What helps, honestly:

  1. Run --headed with a persistent --profile-dir, one profile per server (Chrome locks a profile while it is in use). A person clears a CAPTCHA or signs in once in the visible window; cookies persist for later runs.
  2. When the agent hits a wall it calls wait_for_human: it pauses, you solve the page in the window, and it resumes from the same page.
  3. For pure discovery (finding which pages to read), use a search API; it is more reliable than scraping a results page. Ostler is best at reading the pages you already have URLs for and at filling forms.

Do not spoof the user agent or try to hide automation; it is unreliable and not something Ostler supports.

If it still fails, open an issue with the output of ostler doctor and your OS and Chrome version.

↑↓ to moveEnter to openEsc to close