Repository navigation
Explain or refuse the errors that kept connectors stuck - #1437
Merged
Merged
Conversation
From the Cloud weekly stuck-users report: connectors that failed every call with an error that did not say what to fix. - Hints for Gemini 429 without a free tier (limit 0) vs a rate limit, 402 prepaid credits, Odoo JSON-2 "No database is selected" and "User not authenticated", Etsy account without a shop, Zoho CRM without API access, Bitrix24 HTML 404, Companies House key, Google "API key not valid", unreachable TallyPrime / JTL-Wawi (Cloud vs self-hosted) and an offline tunnel. - A 401 no rule covers repeats the adapter's verifyHints, and credential hints link the connector's page. - Odoo "No database is selected" names a path after the host and the databases the address serves. - Refuse placeholder values, values the adapter pattern refuses and keys pasted twice at verify, install and in the variable editors. - Do not send an empty bearer when a pasted refresh token is missing. - Probes for YouTube Data, Companies House and Bitrix24, so a wrong key fails at setup; Bitrix24 webhook URL pattern.
This was referenced Nov 2, 2026
The server now enforces adapter patterns; some working connectors hold values in a shape that means one thing but missed the pattern: - telegram-bot: strip whitespace from TELEGRAM_BOT_TOKEN. - bitrix24: cut a method name or query after /rest/<id>/<code>/. - digisac: accept accounts on .digisac.io. - substack: keep refusing a profile link, saying a profile is not a publication. Specs cover each case, the weclapp host-to-tenant normalisation and stored Etsy values that an unrelated edit leaves alone.
helpcodeai
force-pushed
the
fix/stuck-connector-errors
branch
from
November 2, 2026 09:31
a5b5092 to
3be0b42
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The Cloud weekly stuck-users report lists connectors that fail every call with an error that does not say what to fix: a model hits a Gemini model without a free tier on its first call, an Odoo address saved with
/webafter the host, a MySQL host left as the literalhost, a key pasted three times, an eBay connector with no refresh token sending an empty bearer. This PR either catches these when the connector is set up or edited, or answers the failing call with what the user has to change and where.Most of it reaches installed connectors without "Apply update": call-time hints live in code (
error-hints.ts), and the adapters'verifyHints,probeandenvVarMetaare read from the catalog when used. NoendpointMappingchanged.Changes
Call-time hints (
packages/backend/src/mcp-server/error-hints.ts)limit: 0on afree_tiermetric (the model has no free tier and the project has no billing, so usegemini-3.1-flash-liteor enable billing), any other 429 (rate limit, wait once), and 402 (prepaid credits used up, top up in AI Studio). The 402 body also saysRESOURCE_EXHAUSTEDand used to get the quota hint.ODOO_DBand at a path after the host (/web,/odoo) inODOO_URL. A 401 "User not authenticated, use an API key" (no key sent) now gets its own hint, separate from "Invalid apikey" (expired key).NO_PERMISSION/Crm_Implied_Api_Access: the Free edition has no API access, and on paid editions the profile needs API Access.*.bitrix24.*hosts or thebitrix24adapter, so Bitrix24 boxes on their own domain are covered too.rest.engine.tsBASIC_AUTH).*.googleapis.com(YouTube Data and similar).ECONNABORTED,ETIMEDOUT, …). On Cloud the hint says the host must be reachable from the internet (a tunnel such as Cloudflare Tunnel, or port forwarding with HTTPS), or AnythingMCP must be self-hosted next to it. On self-hosted it says to check the network path from this server. An ngrok error page (seen on a TallyPrime 404) is read as "the tunnel is offline".verifyHints["401"]/auth_failed. Credential hints end with the connector's page URL (connectorPageUrl), so a connector saved without a passing check hears the setup advice at its first failing call.dynamic-mcp-tools.tspasses the adapter slug, itsverifyHints, the page URL and the deployment mode. For Odoo "No database is selected" it also makes one unauthenticated request that lists the databases at that address (odooNoDatabaseAdvice, reusing the Name the right Odoo database when the entered one does not exist #931 lookup) and names a path after the host.Refused at setup and on save (
packages/backend/src/adapters/env-var-checks.ts, new)host,hostname,server,your-host,yourdomain, bareexample.com/www.example.com,your-api-key,PASTE_KEY_HERE,<...>,TODO,changeme,xxx. The rules are deliberately narrow: subdomains of example.com, single-label hosts such aserp,localhostand IPs are accepted.atlassian.jsonis not touched.envVarMeta.patternis now enforced on the server, not only in the setup form and the chat install.verifyCredentials(returnsfields, which the setup page shows under each field),importAdapter("Save anyway" and chat installs, 400invalid_valueswithfields),PUT /connectors/:id/env-varsandPUT /connectors/:id. The editors check only values the request changes, so a stored bad value never blocks an unrelated edit. Backup import (restore) is left alone.OAuth connector without a token (
oauth2-token.service.ts)Authorization: Bearer11 times and got eBay's "Missing access token". Now, when the refresh-token grant has an emptyrefreshToken, no stored token and noauthorizationUrl, the call stops before any request with "no access token and no refresh token yet: open and enter the refresh token". Connectors with a browser sign-in already got "not authorized yet: open and click Authorize" (setupStatus === 'needs_authorization'andgetAccessToken), so that flow is unchanged. The existing spec that pins an empty token for a connector with norefreshTokenfield still passes.Adapters
youtube-data:probe(videoCategories, part=snippet, 1 quota unit) andverifyHintsfor 400 and 403. Why the YouTube connectors were not caught at setup: the adapter had no GET without required parameters, sopickProbefound nothing, verify returnedskipped: no_probe, and the setup completed without any check. None of the 3 failing connectors hadsetup_saved_unverifiedorsetup_verify_failed.companies-house: the same root cause (no probe). Adds aprobe(search with 1 result),verifyHints400/401, andenvVarMetawith link, help and a lenient pattern (no spaces or colon, at least 20 characters). The instructions now say to pick a Live application. I did not add a strict UUID pattern because I could not confirm that every valid Companies House key is a UUID.bitrix24:envVarMetapattern requiring…/rest/<user_id>/<code>/, with a patternMessage pointing to Developer resources → Other → Inbound webhook. Also aprobe(scope) andverifyHints401/404. The failing connector held a CRM kanban URL.tallyprime,jtl-wawi:verifyHints.unreachablemention a tunnel or port forwarding on Cloud and a self-hosted install.TELEGRAM_BAD_TOKEN_HINT, and the adapter has a probe). Only 2 of the failing workspaces hadsetup_saved_unverified. These connectors now also get the connector-page link.Docs:
docs/tool-definition.mdnow covers where patterns and placeholder checks apply, call-time use ofverifyHints, and when to declare aprobe.Behaviour on Cloud and self-hosted
DEPLOYMENT_MODE=cloudit asks for an internet-reachable address (tunnel or port forwarding) or a self-hosted install; self-hosted (the default) asks to check the network path from this server.FRONTEND_URL, asconnectorPageUrlalready does. Without it, no link is added.Gemini default model
Per https://ai.google.dev/gemini-api/docs/pricing (checked today),
gemini-3.1-flash-lite(the default text model) is free of charge on the Standard tier. Every 429 withlimit: 0in the last 21 days came from models without a free tier:gemini-3.1-pro-previewand the image models (gemini-3.1-flash-lite-image,gemini-3.1-flash-image,gemini-3-pro-image,gemini-nano-banana-2.1). A generate call in the setup check would therefore pass for these users and catch nothing, so I left the probe asgemini_list_models. The fix is the distinct hint, which names the free text model and billing.Not done / needs a larger design
ks/ssandidfailed the adapters' own patterns, which the server now enforces).Type
Testing
Commands run (Node from the repo's lockfile,
npm ci --ignore-scriptsat the root,npx prisma generateinpackages/backend):node scripts/regenerate-catalog.mjscatalog.tsdiff (it imports the JSON files)node scripts/validate-adapters.mjs --warnpackages/backendnpx tsc --noEmit -p tsconfig.jsonpackages/backendnpm run lint--fixrewritespackages/backendnpx jest --maxWorkers=2on the 21 touched or covering spec files: env-var-checks, error-hints, error-hints.stuck-connectors, odoo-database-hint, oauth2-token.service, adapters.service, connectors.controller, connector-setup.service, adapters.controller, dynamic-mcp-tools, dynamic-mcp-tools.per-user, secret-guard.flows, catalog, catalog-search, env-var-meta, connector-setup-status.util, and the static specs of jtl-wawi, tallyprime, bitrix24, odoo, youtube-datapackages/frontendnpx tsc --noEmit -p tsconfig.jsonpackages/frontendnpm run lintThe full backend suite was not run, to keep the shared machine's load down. No Playwright run: the frontend change is 5 lines on the setup page that show the server's field messages.
Checklist
npm test): only the targeted specs above were runRelated Issues
From the AnythingMCP Cloud weekly stuck-users report; no public issue.