Troubleshooting
Find your symptom, check, fix. Start with the Integration Health card — its rows name most problems — and Test connection. If you contact Conviro support, attach the diagnostics bundle.
Each heading has a stable anchor (#symptom-…) so a message can link here.
Installation and upgrade
Composer: "You must be using the interactive console to authenticate" / HTTP 401 from repo.conviro.io
The Composer password is not a valid Conviro API key (a widget public key does not work). composer config http-basic.repo.conviro.io api <API key> — the username is literally api. See Installation.
"Class … does not exist" or a blank admin after upgrading
The store is in production mode and setup:di:compile (or setup:static-content:deploy -f) was skipped, or setup:upgrade cleared the generated code and static files and the compile has not run yet. As the owner of the Magento files (not root), run: bin/magento maintenance:enable && bin/magento setup:upgrade && bin/magento setup:di:compile && bin/magento setup:static-content:deploy -f en_US <your store locales> && bin/magento cache:flush && bin/magento maintenance:disable. Unstyled pages or 404s for .js / .css files in one language only: that locale was not named in the static deploy. Each step: Installation › Upgrading.
The storefront still shows the old widget after upgrading (an inline cw('init' script, a nonce on it, or Check storefront says the loader is from an older release)
Magento serves templates from minified copies in var/view_preprocessed/ and, in production mode, does not notice that the module's template changed; static files come from pub/static/. Both can outlive an upgrade — measured on a 2.4.9 test store upgraded from 1.3.5, and typical of release-directory deployments that carry var/ over. 1.4.1 removes the module's own preprocessed templates on every setup:upgrade. For an older upgrade, or to be sure, in maintenance mode: rm -rf var/view_preprocessed/pub/static/vendor/conviro (…/app/code/Conviro for an app/code install), then bin/magento setup:static-content:deploy -f en_US <your store locales> and bin/magento cache:flush — and flush Varnish / your CDN if one caches pages. Then Check storefront on the Integration Health card.
Full-page cache: on a Magento 2.4.9 test store (file cache, 2026-09-27) bin/magento cache:flush and cache:clean full_page left the pre-upgrade page in var/page_cache/ and the storefront kept serving the old widget until the files were removed (rm -rf var/page_cache/*, in maintenance mode). Check the served page with Check storefront after every upgrade.
"Permission denied" in var/, generated/ or pub/static/ after upgrading
The upgrade ran as root, so the files it created belong to root and the web server cannot write them. Give them back to the web-server user (for example chown -R www-data: var generated pub/static pub/media, with your own user and group) and run the upgrade steps as that user next time (Installation › Upgrading).
No "Conviro Setup" menu for an admin user
Their role lacks Conviro_AiChat::setup (new in 1.4.0). See custom admin roles.
Connecting
The approval page says API access is not included in the plan
Connecting a Magento store needs a Conviro plan with API keys. Upgrade the plan, then start again from the wizard.
"The answer from Conviro does not belong to the connect started here (state mismatch)" / "no valid connect code"
The callback reached a different admin session, the 10-minute handshake expired, or the page was reloaded. Nothing was changed. Click Connect to Conviro again in the same browser session and approve within a few minutes (the code lasts 5).
Connect or Save Config: "Cannot reach …", Connection row "Magento cannot reach Conviro"
The server cannot open https://api.conviro.io (port 443). Allow outbound HTTPS from the Magento server (and any egress proxy) to api.conviro.io. See Networking and firewalls.
"only calls a store over HTTPS, set the secure Base URL" / "Invalid store URL" / "does not resolve"
Conviro refuses to send credentials over plain http, to a host that resolves to a private address, or to a host it cannot resolve. Set the default store view's Secure base URL to a public https:// address and Save Config.
Authentication row: "Conviro uses the legacy bearer token"
Magento rejected the OAuth 1.0a signature. Most often a load balancer, CDN or proxy terminates HTTPS and does not tell Magento: make it send the header named in web/secure/offloader_header (default X-Forwarded-Proto: https), then Save Config. The store keeps working on the bearer token meanwhile.
Connection row: HTTP 401 — key wrong, revoked or expired
Paste an active key (or run Connect to Conviro again) and Save Config. Events held meanwhile are re-queued automatically.
"Conviro's network protection blocked this server — contact Conviro support"
Symptom. The Connection row (or wizard step 1's Outbound connection, or the Save Config message) says Conviro's network protection blocked this server. Before 1.4.1 the same situation showed as "HTTP 403 — the API key lacks the kb:write scope", events were held as a credentials problem, and the automatic OAuth migration stopped as failed — none of which a new key fixes.
Cause. api.conviro.io is served through Cloudflare. Its bot protection answered this server with a challenge page ("Just a moment…", HTTP 403 with cf-mitigated: challenge) instead of passing the request to the Conviro API. It happens to servers at some hosting providers whose address ranges score as automated traffic, and nothing in Magento causes or fixes it. Check from the server:
curl -s -o /dev/null -w '%{http_code} %header{cf-mitigated}\n' https://api.conviro.io/api/magento/module-version
curl -s https://api.ipify.org; echo # this server's public (egress) IP address
200 is fine; 403 challenge is this problem (curl 7.84 or later prints the header).
Fix. Contact Conviro support at [email protected] with the egress IP address the second command prints (and the time you saw the message); Conviro lets that server through. Nothing needs to change in Magento: since 1.4.1 queued events are kept and retried, the OAuth migration keeps retrying, and every call carries the User-Agent Conviro-Magento/<version> (Magento <version>; +https://useconviro.com), so Conviro can recognise the module's calls. If you run an egress proxy, make sure it passes the User-Agent through unchanged. Click Test connection once support confirms.
Connection row: HTTP 403 — lacks kb:write
The pasted key has neither kb:write nor magento:module. Create one that has one of them, or use Connect to Conviro, which creates the right key. (Since 1.4.1 this row appears only for the Conviro API's own answer; a 403 page from something in between is reported as network protection or as "not an answer from the Conviro API".)
"The API key belongs to another Conviro workspace"
Save Config to connect the store to the key's workspace, or paste the key of the workspace the store was connected to.
Events and sync
Events stay "waiting" / Cron row "never run the Conviro delivery job"
Also shown as the admin message "Magento cron has not run the Conviro delivery job for N minutes" (1.4.1).
Magento cron is not installed or not running. As the owner of the Magento files (not root):
crontab -lmust list a line runningbin/magento cron:runevery minute (* * * * *). If it is missing:bin/magento cron:install(writes it for the current user — run it as the Magento file owner).- Run
bin/magento cron:runby hand and check it completes without errors; then look atvar/log/cron.logandvar/log/exception.log. - If cron runs but the Conviro jobs never do:
bin/magento cache:flush. - Container / managed hosting without a user crontab: the platform's scheduler must run
bin/magento cron:runevery minute (Adobe Commerce Cloud:cronsin.magento.app.yaml).
The Details rows Delivery heartbeat and Maintenance heartbeat show the last run, the last success and the last failure (with its message) of the two every-minute jobs.
"N event(s) are waiting to be sent to Conviro; the oldest for N minutes. Cron runs, but delivery fails …" means cron is fine and Conviro does not accept the events: the message names why (network protection, credentials, Conviro unreachable). Click Test connection on the Integration Health card.
Orders / events row: "N event(s) held: Conviro refused the store's credentials"
401/403 from the Conviro API. Fix the key, Save Config — held events go back to the queue. (A challenge page of Conviro's network protection does not hold events since 1.4.1: they stay retrying — see network protection.)
"N event(s) failed permanently"
Conviro refused them (a 4xx other than 401/403) or seven attempts over about 10 h 43 min (7 attempts) failed. Read the last error, fix the cause, then Retry failed, or Repair failed items to rebuild them from current data.
Events refused 401 api_key_not_registered / magento_not_connected
Conviro accepts a store's events only with the API key that registered the store's connection (security fix, PR #832). api_key_not_registered: the key the store sends with did not register it — typically a key changed without a successful Save Config, or a workspace whose Magento connection was made from the Conviro dashboard only. In Magento open Stores > Configuration > Conviro > AI Chat and click Save Config (or run the setup wizard): the store registers again with its key and held events go back to the queue. magento_not_connected: the workspace has no active Magento connection — connect the store (Stores > Settings > Conviro Setup).
"Conviro has no products from this store yet" / the assistant does not know a product
- Sync Products to KB must be on; then click Re-sync catalog.
- Products changed by Magento's catalog import or the Update attributes mass action are not sent as events — run Re-sync catalog.
- Only enabled, website-assigned products visible in catalog and/or search are sent; disabled products are removed from the assistant's knowledge.
A sync job says "Not moving for over 15 minutes"
Magento cron is not running it. Install / fix cron; the job resumes where it stopped. "Paused until the waiting events are delivered" is normal back-pressure (1,000 events waiting), not an error.
A re-sync button answers that the switch is off
Catalog and inventory need Sync Products to KB; order history needs Send Order Events; customer import needs Customers ticked in wizard step 5.
Orders of one store view never reach Conviro
That store view is not selected in wizard step 4, Send Order Events is off for its website, or the module is disabled for it (Enable = No at store-view scope).
Cart recovery and payment assist
"Cart & payment events" row: switched on but not confirmed
Since 1.4.0 these send shopper data only after you confirm: the link in the admin message (confirms only the ticked features, starts no sync — 1.4.1), wizard step 5, or Confirm cart / payment data sharing = Yes and Save Config. See Cart recovery and payment assist.
Cart recovery is confirmed but no e-mail goes out
A cart event is sent only for a cart with an e-mail (logged-in shoppers, in practice) and at least one item; Conviro schedules the e-mail only for a cart worth at least 1 and sends it 60 minutes after the last change to the cart; an order from the same e-mail cancels it. Carts changed only through REST/GraphQL cart APIs do not produce the Magento event the module listens to.
Webhooks from Conviro
Webhooks row: "N webhook(s) … were rejected in the last 24 h"
Save Config to re-sync the signing secret with Conviro. Rejections that continue afterwards are requests not sent by Conviro (for example a scanner). A WAF that rewrites request bodies also breaks the signature — see Networking.
Conviro dashboard: "Conviro → store webhooks: Paused … the store answers with a redirect" / your access log shows POST /conviro/webhook/receive answered 302 and repeated POST /
Cause. Module 1.3.x cannot receive Conviro's webhooks: its receive controller has no CSRF exemption, so Magento answers every webhook POST with a 302 redirect to the home page. Until 2026-09-26 Conviro's sender followed that redirect and re-sent the POST to the address it named (your home page), up to three hops — measured on the first reporting store: every event became one POST /conviro/webhook/receive (302) plus three POST /. Nothing was received. Since 2026-09-26 Conviro never follows a redirect on a webhook: a 3xx is a failed delivery, retried not at all, and after 5 in a row over at least 15 minutes the webhook is paused (Conviro's operators are alerted).
Fix.
- Update the module to 1.4.1 (Installation › Upgrading). 1.4.x answers signed webhooks with 200.
- Open Stores › Configuration › Conviro › AI Chat once and click Save Config: the store registers again, and Conviro re-checks a paused webhook automatically a few seconds later — with a signed test delivery; only a 2xx resumes it.
- Or, on the Conviro dashboard (Integrations › Magento › Delivery health), click Verify and resume. It stays paused, with the reason, until your store answers 2xx.
- If it still fails: a redirect of your own (http → https, www → non-www, a store code in the path) — register the final https base URL; a WAF challenge (
challenge) — allow Conviro (Networking); 401/403 — Save Config to re-sync the signing secret.
The Magento Webhooks row shows the last verified webhook; after the fix it shows one within minutes of the next chat session.
Storefront widget
The chat widget does not appear
- Enable is Yes and Widget Public Key is set for that store view.
- A Content Security Policy in report-only or enforced mode must allow
https://cdn.conviro.ioandhttps://api.conviro.io(the module ships a CSP whitelist for Magento's CSP module; a CSP set elsewhere — web server, CDN — needs the same hosts, pluswss://api.conviro.io). - Full-page cache: after changing widget settings,
bin/magento cache:flush. - Since 1.4.1 the widget loads on the first interaction (or after 4 s) by default — scroll or press a key before deciding it is missing, or set Load the Chat Widget = Immediately while testing.
- Click Check storefront on the Integration Health card: it reads the page visitors get and says whether the widget configuration and the module's loader are on it, whether the served loader file is current, and whether a theme override or a pasted snippet starts a second widget (Storefront widget row).
- A theme that overrides
Conviro_AiChat::widget.phtmlor removes theconviro.aichat.widgetblock controls the widget, not the module: the card's Storefront widget row names the theme and files.
Signed customer identity and My orders (1.5.0, unreleased)
1.5.0 (unreleased), read 2026-09-27 on feat/magento-1.5.0-customer-hub and its module / UI branches. First open the Customer Experience & Identity card (Integration Health) and click Test identity bridge: most causes below show up there. The Customer identity runbook walks the card in order. What the feature is: Signed customer identity and My orders.
A signed-in shopper is still asked for an order number / never "connected"
Every one of these must hold; the first that does not is the cause.
- Module 1.5.0 installed and
setup:upgraderun (the card exists). - Enable signed customer identity = Yes for that website (and the widget is enabled with a public key in that store view).
- The card's Signed identity line says the key is registered.
- Conviro switched
magento_identity_bridgeon for your workspace (card › At Conviro). For My orders alsomagento_my_orders, and Show verified shoppers their own orders = Yes on the same website. - Conviro received the store's announcement (card › At Conviro; if not, Save Config).
- The store view the shopper is in is mapped and selected at Conviro (card › Store views / At Conviro; setup wizard step 4). An unmapped store view is refused — counted as
invalid. - The server clock is within 30 s of Conviro's (card › Clock).
- The store is on OAuth 1.0a (Authentication row = Pass) — My orders only.
- The storefront page is the one the module renders (Luma / Hyvä) with the current loader: after the upgrade you deployed static content and flushed the caches (Check storefront, Storefront widget row). A headless frontend has no bridge (Headless).
- The shopper opened the chat: the bridge never runs on page load.
The widget's greeting by first name works without any of this — it is display only and proves nothing.
"Signed identity: the Conviro backend does not support it yet"
The Conviro API answered 404 to the key registration: it is older than 1.5.0. Everything else works as with 1.4.x. Nothing to change in Magento; the next Save Config after Conviro's backend is updated registers the key.
"Conviro refused this store's key"
The card shows Conviro's reason:
| Conviro's answer | Cause | Fix |
|---|---|---|
409 store_url_in_another_workspace — "Another Conviro workspace has an active connection to this store…" | two workspaces are connected to the same store URL; signed identity is refused for both | disconnect the store from the workspace that should not have it, or contact Conviro support |
409 store_disconnected | Conviro has the store as disconnected | Setup wizard › Reconnect |
409 store_not_registered | the store has not registered with this key yet | Save Config (registers the store first) |
409 kid_conflict, key_revoked, key_retired | the key id belongs to another key or installation, or the key was retired / revoked | Rotate identity key (a new pair) |
403 key_bound_to_other_store | the API key was minted for another store URL | reconnect with the setup wizard from this store |
| 403 (scope) | a hand-pasted API key without magento:module | use Connect to Conviro in the setup wizard |
| 400 | the public key or kid is malformed | Rotate identity key; if it persists, contact support with the diagnostics bundle |
"The PHP sodium extension is not loaded"
The PHP that runs Magento (web and cron) has no sodium extension, so the store cannot sign. Composer refuses to install 1.5.0 without ext-sodium; this state appears when the web server's PHP differs from the CLI's. Enable the extension for that PHP (e.g. extension=sodium in its php.ini) and restart PHP-FPM.
Failed verifications in the card or the dashboard
The card's Activity line and the dashboard show failed verifications by reason. What each means:
| Reason | Usually | Fix |
|---|---|---|
expired | the assertion or the challenge ran out (60 s / 120 s) before Conviro got it: a slow network, a tab left open, or a server clock behind Conviro's (a clock more than 30 s ahead is invalid) | check the clock (below); occasional ones are harmless (the widget retries once) |
invalid | the signature, key or claims did not check out — including a store view not mapped (or not selected) at Conviro, a key registered for another store URL, a wrong holder secret, or a server clock more than 30 s ahead | Test identity bridge: it names the failing step; map / select the store view; Save Config or Rotate identity key |
replayed | the same assertion or challenge was used twice: a reload race (harmless when rare), or a cache or CDN serving one bootstrap answer twice | if it is frequent: the bootstrap is cached |
not_available | signed identity is off at Conviro, the store has not announced it, the module is older than 1.5.0, the merchant switch is off, or the integration is inactive | the card's first-blocker line names which (runbook) |
too_many | the shopper's chat already held five live verifications (one per tab, each valid 15 minutes): many tabs or reloads at once. A request over the rate limit (10 in 5 minutes per chat, 60 a minute per IP) is answered 429 rate_limited and is not counted here | nothing, unless it is constant (a script) |
unavailable | Conviro could not check at that moment (an error at Conviro, not in the store) | try again; persistent → Conviro support |
account_switched | not a failure — counted as a success: another customer signed in on the same browser; the previous verification was dropped | nothing (expected) |
The admin card's Activity line gives the top reason with the same meaning and links this table, or the runbook gate for expired (clock) and invalid (store view mapping) — module 1.5.0 Phase 5 P5-08, 2026-09-27; Conviro's exchange code of the same date.
The bootstrap request fails (browser network tab)
GET /conviro/identity/bootstrap answers JSON {"error": …}:
| Answer | Cause | Fix |
|---|---|---|
404 not_found | signed identity is off for this website, or the widget is off / has no public key in this store view | switch it on for the website; check Enable and Widget Public Key |
404 not_available | the store has no registered key, or no Conviro tenant / integration id yet | Save Config; see the card's key state |
400 xhr_required, cross_site, bad_destination, bad_origin | not the module's own same-origin request: a proxy stripped X-Requested-With, the page runs on another origin than the store view's base URL (a CDN host, www. vs. bare domain, http vs. https), or a theme / script called it | serve the storefront on the store view's configured secure base URL; do not strip X-Requested-With; never call the route yourself |
400 bad_parameters | malformed n / wsh — not sent by a current loader | deploy static content, flush caches |
401 not_logged_in | Magento has no signed-in customer for this session (signed out elsewhere, session expired, back / forward cache) | expected; the widget shows signed out |
429 rate_limited | more than 10 signatures a minute for one Magento session | wait a minute |
503 unavailable | an error in the store (see var/log/system.log, "[Conviro] Identity bootstrap failed") | fix the logged cause |
Many replayed failures / the loader reports bootstrap_cached
A cache in front of Magento (Varnish rule, CDN "cache everything", a reverse proxy) served a stored bootstrap answer: the nonce inside it is not the one the widget sent, so nothing is verified — this is fail-closed, never another shopper's identity. Exclude /conviro/identity/bootstrap from every cache and let the Cache-Control: no-store, private header through. Not tested behind a real CDN or Varnish.
"This server's clock is N seconds ahead of / behind Conviro's"
Conviro allows 30 seconds of clock difference on an assertion the module signs for 60 seconds (iat = nbf = this server's clock, exp = iat + 60). What that means, exactly as Conviro's verifier decides (2026-09-27):
| this server vs Conviro | effect | card |
|---|---|---|
| more than 30 s ahead | a fresh assertion is dated in the future: every sign-in link fails (invalid) | first blocker Clock |
| 90 s or more behind | the assertion has expired when it arrives: every sign-in link fails (expired) | first blocker Clock |
| 31–89 s behind | still accepted, but only when it reaches Conviro within 90 − N seconds of signing; a slower page fails as expired | warning line, not a blocker |
| within 30 s | accepted (at least 60 s for the network) | In step with Conviro |
The card's Clock line names the seconds, the direction and when it was measured. Synchronise the server clock: timedatectl set-ntp true, chrony or ntpd.
Where the number comes from: the card's At Conviro › Clock line and Test identity bridge compare with Conviro's clock directly. Phase 5 (branch feat/magento-1.5.0-p5-module, unit-tested): the module also reads the Date header of every answer from Conviro's API (never of a challenge page or a proxy error page) — so the card's first-blocker line names the clock even before Conviro is asked or while it cannot be reached, and the 15-minute module-health report tells Conviro (identity.clockSkewSec, seconds, positive = this server is behind; left out when there was no reading in 24 hours). The reading is accurate to about half the request's round trip plus a second.
"Order listing permission missing" / "Sipariş listeleme izni eksik"
See Integration Health › Order listing permission missing: Repair access on the card.
The shopper sees "Order details aren't available in the chat for this store"
A verified shopper's order read was refused before reaching any order (not_available). The dashboard's reason:
| Reason | Cause | Fix |
|---|---|---|
permission_missing | Magento answered "not authorized": the integration lacks Conviro_AiChat::api_customer_orders | Repair access |
my_orders_disabled | Show verified shoppers their own orders is off for that website, or magento_my_orders is off at Conviro, or the store did not announce myOrders | switch it on / ask Conviro / Save Config |
store_auth_mode | the store still uses the legacy bearer connection | Save Config to move to OAuth 1.0a (bearer) |
feature_absent | the store's module has no identity route (older than 1.5.0, or a downgrade) | upgrade the module |
The shopper still gets the account-page link and the guest lookup.
The shopper sees "We can't load your orders right now"
The store did not answer usefully (unavailable) — never shown as "no orders":
| Reason | Cause | Fix |
|---|---|---|
timeout | the store took more than 5 seconds | check the store's load; Test connection |
store_error | 5xx, a redirect, a network or TLS error, or a URL the store-URL guard refuses | the store's var/log; store URL refused |
store_auth_failed | Magento refused Conviro's OAuth signature | Save Config (or Reconnect) |
contract_error | an answer this Conviro version does not understand (module / backend mismatch) | update the module; report it to Conviro support |
rate_limited | more than 20 order reads in 5 minutes for one shopper, or 120 a minute for the store (the widget says to try again in a minute) | nothing, unless it is constant |
The shopper sees "Sign in to see your orders", "You've signed out" or "Your secure connection to the store has expired"
Magento refused the signed session on the order read and Conviro ended the verification. Expected after a sign-out, a password change or reset, a customer deletion, an admin or brute-force account lock (customer_locked), another customer signing in on the same browser, or when the 16-minute binding ran out (binding_expired; binding_unknown = the store no longer has that binding). The widget reconnects once by itself; a signed-in shopper can tap Reconnect. customer_mismatch and store_mismatch should never happen — Conviro logs them as errors; send the time to Conviro support. integration_changed means the chatbot now points at another Magento connection: the shopper reconnects.
"We couldn't find that order in your account" / "We can't show that order in this account"
The number is not one of this customer's orders visible in this store view (or website): another customer's, another store view's under This store view only, a status your storefront hides, or no such order — deliberately the same answer (not_in_account). order_ref_invalid: a card from an earlier chat or another session was tapped — ask again for My orders. To show orders of every store view of the website, set Orders a verified shopper sees = Every store view of this website.
Guests are not asked for a code although Ask guests for a one-time code is on
Expected on 2026-09-27: the Conviro side of guest verification is not built yet. Guests look orders up with the order number and checkout e-mail, as before.
Performance
The Conviro configuration page is slow
With Conviro unreachable, a render can wait about 3.5 s once a minute (up to about 7 s when the version cache is cold too). Fix the outbound connection; the storefront is not affected.
Still stuck
Download diagnostics and send it to Conviro support ([email protected] per the module's composer.json). The bundle contains no secrets or customer data.