Error codes

482 codes. Every API error carries {code, message, hint, docs}. The docs link lands on that code's anchor here.

The envelope
{
  "error": {
    "code": "bot_already_in_meeting",
    "message": "A bot is already in that meeting.",
    "hint": "Reuse it, or make it leave first.",
    "docs": "http://localhost:3000/errors#bot_already_in_meeting",
    "details": { "bot_id": "bot_..." }
  }
}

Read hint before anything else. It is written for the caller, not for a human reading a log.

Forms and response delivery

form_invalidHTTP 400

A document, answer or argument is invalid.

Fix: Correct details.fields or details.issues and retry.

A form resource is missing or inaccessible.

Fix: List accessible forms and responses. Check the published URL for public reads.

The actor cannot perform an owner operation.

Fix: Use the creator or workspace owner, or request explicit access.

The revision changed or a submission key was reused for different content.

Fix: Read the latest revision and merge changes. Reuse a submission key only for the same response.

form_closedHTTP 409

The form is closed, expired or at its response limit.

Fix: Ask the owner to reopen it or update its deadline or limit.

The form accepts responses only through a personal invitation and none was supplied.

Fix: Submit from the invitation link the owner sent (its invitation token), or ask the owner for one.

form_leaseHTTP 409

An event receipt expired or no longer matches the lease.

Fix: Claim again and reconcile external work using the event ID.

The request exceeds 128 KiB.

Fix: Reduce the JSON body size.

Brand kit (logo and colours)

The uploaded file is not an image the brand kit reads (or an iPhone HEIC the server cannot decode).

Fix: Send the logo as SVG, PNG, JPEG, WebP or GIF. From an iPhone, export or share it as PNG or JPEG.

The upload is a design file (PDF, AI, EPS, PSD) rather than an image.

Fix: Export the logo from the design tool as SVG (best) or a PNG with a transparent background, at least 1000 px wide.

The SVG declares external entities or has no drawing; scripts, handlers and outside references are removed, entities are refused.

Fix: Export the SVG again from the design tool (plain SVG, no external links), or send a PNG.

The image bytes could not be decoded.

Fix: Open the file on your computer to check it is not damaged, then send it again as PNG or SVG.

logo_emptyHTTP 400

The image has nothing drawn in it: fully transparent or a single flat colour.

Fix: Send the file that contains the logo itself.

The logo file is larger than 10 MB.

Fix: Send a smaller export: an SVG, or a PNG about 2000 px wide is plenty.

The brand has no logo and no chosen colour, so there is nothing to build colours from.

Fix: Upload a logo with upload_brand_logo or choose a colour with set_brand_colors first.

The palette id is not one of the options this brand kit offers now.

Fix: Call get_brand_kit and use one of palettes[].id.

A brand colour is not a 6-digit hex colour.

Fix: Send colours as #RRGGBB, for example #0F5FCC.

A page, form or booking page to apply the brand to does not exist in this workspace.

Fix: List the resources (list_bio_pages, list_forms, get_booking_page) and use their ids.

Authentication and setup

An owner listener action, topic, lease extension or standing instruction is invalid.

Fix: Use get_agent_listener_setup and create_agent_listener, then copy the returned listener id exactly.

A listener does not exist or belongs to another connected agent identity.

Fix: Call list_agent_listeners using the same OAuth connection or API key that created it.

A delivery is not part of the selected owner listener.

Fix: Inspect get_agent_listener_health and use one of its event ids.

An event receipt expired or no longer owns the listener lease.

Fix: Claim the event again and reconcile any external effect before retrying.

A caller tried to replay an event that is not waiting for manual attention.

Fix: Let pending delivery continue. Replay only after a dead event has been inspected and reconciled.

User API credential and request encryption is not configured.

Fix: The operator must configure INSTANCEOFAI_ENCRYPTION_KEY before saving credentials or executing custom integrations.

The exact custom integration tool grant reached its UTC daily attempt limit.

Fix: Wait for the next UTC day or ask the owner to review the tool grant. This limit does not estimate provider charges.

A resumed or newer deletion request superseded this attempt.

Fix: Review the current deletion status in Settings before retrying. No files were erased by this stale attempt.

The workspace owner started deletion and paused new registered requests.

Fix: The owner can retry deletion or resume requests in Settings, Data and privacy. Resuming does not undo subscription cancellation.

A chat receipt expired, the conversation changed or a request key was reused with different content.

Fix: Read current state, reconcile a previously sent reply and claim current work. Never resend a stale answer.

A permission request is expired, inaccessible or requires human review.

Fix: Use the requesting connection to create a fresh request, then ask its authorizing human to review it.

unauthorizedHTTP 401

No API key, or a key that is not in this workspace.

Fix: Send `Authorization: Bearer iai_...`. No key yet? While the workspace has zero keys, POST /api/v1/setup/bootstrap from the machine instanceofai runs on, or run `npx instanceofai init`.

A scoped API key called something outside its scope (a read key writing, a bio key touching meetings).

Fix: Create a key with the scope the task needs: "*" for everything, "read" for read-only access, "bio" for the link-in-bio page (create_api_key {scopes} or /settings). Keys can also carry an expiry.

POST /api/v1/keys with a scope that does not exist.

Fix: Use "*", "read", "bio" or "booking".

POST /api/v1/setup/bootstrap after at least one key exists.

Fix: Bootstrap is a one-time zero-key path. Create another key with `npx instanceofai key create <name>`, at /settings, or with the create_api_key tool.

Bootstrap called from a non-loopback address (or through a proxy) without INSTANCEOFAI_ALLOW_REMOTE_BOOTSTRAP=1.

Fix: Create the first key on the machine that runs instanceofai and copy it. Only set INSTANCEOFAI_ALLOW_REMOTE_BOOTSTRAP=1 if you deliberately want an unconfigured instance to hand a full-privilege key to whoever asks first.

Deleting an API key id that does not exist.

Fix: GET /api/v1/keys for current ids.

missing_nameHTTP 400

Creating a key or calendar without a name.

Fix: Send {"name":"my-agent"}.

An MCP client registration has no safe redirect address.

Fix: Register at least one HTTPS callback, or an HTTP callback on localhost.

An OAuth authorization request names an unknown client.

Fix: Register the MCP client at /register and retry.

The OAuth callback does not exactly match the registered callback.

Fix: Use one of the redirect_uris returned during client registration.

An OAuth client requests a flow other than authorization code.

Fix: Use response_type=code with PKCE S256.

An OAuth authorization request is missing a valid PKCE challenge.

Fix: Send code_challenge_method=S256 and a valid code_challenge.

An OAuth code or refresh token is invalid, expired, reused or bound to different client data.

Fix: Start a fresh browser connection.

The OAuth resource changed during the authorization flow.

Fix: Use the same MCP resource URL throughout the flow.

An agent polls a pairing before the human approves it.

Fix: Keep polling at the returned interval while the human opens verification_uri_complete.

The revocation endpoint was given a key that no OAuth client was issued, such as an owner or bootstrap key.

Fix: Delete that key from Settings, or with DELETE /api/v1/keys/{id} as the workspace owner.

A hosted deployment would have built a sign in link from the caller's Host header because INSTANCEOFAI_PUBLIC_URL is not set.

Fix: Operators: set INSTANCEOFAI_PUBLIC_URL to the public https address and restart.

A browser pairing expired or was already consumed.

Fix: POST /api/v1/connect to create a new pairing.

An operation references a workspace that does not exist or has been deleted.

Fix: Stop work for that workspace. Sign in and select an existing workspace before retrying.

Workspace erasure encounters registered tasks without completion receipts.

Fix: Wait for tasks to finish and retry deletion. A stopped worker needs support reconciliation; elapsed time alone does not prove completion.

The workspace was frozen by an operator, usually while an abuse report about a public page is looked at.

Fix: Nothing was deleted and the data is intact. Write to support@instanceof.ai to have the suspension reviewed.

use_workspace_tool (or a direct MCP call) names a tool that does not exist.

Fix: Call find_workspace_tools with the task in the person's words and use a name it returns exactly.

An endpoint that serves the signed in dashboard (the search palette) was called with an API key.

Fix: Use the product routes (forms, booking, chat, meetings) or the MCP tools instead.

An app install or permission request was already answered or has expired.

Fix: Check it with get_app_install_request; file a new request_app_install if the apps are still needed.

Plans and meeting profiles

Managed agent pilot has not been enabled.

Fix: Request operator enrollment. Existing plans and MCP connections are unchanged.

A starter request key was reused with different inputs.

Fix: Reuse identical input for retries or choose a new request key.

The active brand allowance is exhausted.

Fix: Archive an unused brand or ask the owner to review /billing.

Archiving a brand would leave associated resources.

Fix: Move or detach its resources first. Content will not be deleted.

A brand or selected resource does not exist in the current workspace.

Fix: List authorized resources and select an active brand.

The workspace automation allowance is exhausted.

Fix: Wait for the monthly reset. No automatic overage is charged.

An API key licensed by an agent seat tried to change something while the workspace subscription is inactive (expired, revoked after a refund, or past the grace period). The same key still reads: REST GET routes and every tool marked read-only, exports of the workspace's own data included.

Fix: Keep reading and exporting with the same key. Renew in /billing and the key writes again with no new key and no repair step. The owner can still change or delete anything from the dashboard in the meantime.

A visitor opened a published chat channel whose workspace cannot answer right now because its subscription is inactive. The visitor sees one short sentence in the channel's language, with no billing detail.

Fix: Nothing for the visitor to do but try later. The owner renews in /billing; the channel, its conversations and its history are kept and the widget answers again at once.

Starting a recording (a bot or an upload) that would exceed the plan's monthly recording hours.

Fix: Upgrade at /settings#plan, or wait for the allowance to reset. `details` carries used_hours, included_hours and period_end. A meeting already recording is never interrupted by this — the check only runs when one is about to start.

The tool or endpoint belongs to an app this workspace has not installed (details.app, details.install_url). Installed apps decide which tools an agent sees at all; a plan decides what they include.

Fix: Call request_app_install {app, reason, scopes} and send the owner the one install_url it returns (apps and permissions are approved together). Poll get_app_install_request; the compact catalogue finds the tools as soon as it is installed, a full catalogue client refreshes tools/list if its host caches it. Nothing was changed.

app_in_useHTTP 409

Uninstalling an app that another installed app needs (details.dependents) or that still has something live: a published page or form, a connected account, a calendar the notetaker follows (details.live).

Fix: Uninstall the dependents first, or turn off and disconnect each listed item. Uninstalling never deletes data.

Installing a connection whose provider this deployment has not set up.

Fix: Choose an app list_apps returns. The operator enables providers; credentials are never supplied by an agent.

A kit (create_suite_starter, prepare_business_operation) would install an app whose data is scheduled for erasure. A kit never cancels an erasure behind the owner's back.

Fix: The owner cancels the erasure on the app's page (/apps/<app>), or installs the app there, which cancels it; then run the kit again. Nothing was changed.

The endpoint belongs to a feature outside this workspace's plan (details.feature, details.plan_required, details.current_plan).

Fix: details.preview holds what the feature would have produced, computed for free. If details.preview_only is true the dashboard is merely previewing a lower plan: turn it off at /settings#plan or with set_plan_preview. Otherwise the plan is a deployment setting (INSTANCEOFAI_PLAN).

invalid_planHTTP 400

set_plan_preview with an unknown plan, or one above the deployment's ceiling.

Fix: Use record, notes, agent or presence, at or below INSTANCEOFAI_PLAN.

A meeting profile id that does not exist.

Fix: list_meeting_profiles shows the built-in profiles (general, daily, one_on_one, customer, interview, strategic, retro) and the custom ones.

A profile config field is out of range or the wrong type.

Fix: The message names the field. Turn seconds are 30..900, warn seconds are below turn seconds, the minutes template is one of the documented names.

set_meeting_profile without a calendar_id, event_id, meeting_id or match_title.

Fix: Say what the profile applies to: a calendar (every meeting in it), one event, one meeting, or a title pattern.

Paid hosted processing has no explicit model configured for its provider.

Fix: Contact support. Operators must configure and validate the hosted model before offering paid execution. No credits are charged.

set_owner_name / the coaching form received a name longer than 80 characters.

Fix: Pass the participant name as it appears in transcripts (e.g. "Rafael"), or null to clear it.

Billing

The hosted model returned no completed answer.

Fix: Credits are released. Inspect any drafts already prepared before starting another request.

A credit reservation already exists for this request.

Fix: Inspect the existing request. Never repeat execution under a new ID without checking effects.

Another subscription is attached to this workspace.

Fix: Manage the current subscription in /billing before starting a new one.

The workspace has already started its suite trial.

Fix: Trials cannot be restarted. Choose a paid plan.

A checkout is pending or its external result is uncertain.

Fix: Finish or reconcile that checkout before trying another.

quote_agent_plan names the agent-usd-v1 contract while it is legacy and this workspace is not on it (details.catalog_id, details.status, details.current).

Fix: Quote the current offer with contract shared-usage-v1 (get_agent_plan_catalog lists it). Workspaces already on agent-usd-v1 keep reading and quoting their contract.

The legacy per seat checkout is called for a workspace that has a suite contract row, including the pending one created at signup.

Fix: Choose a plan in Plan and usage (/billing). This workspace buys from the current catalogue and the legacy plan checkout no longer applies to it.

A trial is requested for a workspace whose contract is priced in USD, or on a deployment that sells the current catalogue.

Fix: Choose a plan in Plan and usage. These plans are sold rather than trialled, and paying starts access immediately.

Usage credits are bought before the workspace has an active plan.

Fix: Open Plan and usage and choose a plan first. Usage credits top up an active plan, and no payment was started.

Provider currency, price or billing cadence differs from the offer.

Fix: The operator must reconcile the product before checkout is enabled.

A checkout request uses an interval other than monthly or annual.

Fix: Choose monthly or annual billing.

A checkout or portal is opened before the Creem key and product IDs are configured.

Fix: Set the CREEM_API_KEY and CREEM_PRODUCT_* variables, then restart.

Creem does not return a checkout or customer portal URL. The subscription webhook answers 503 with this code when the provider is unreachable, so Creem retries it.

Fix: Retry. If the provider continues to fail, contact hello@instanceof.ai.

A permanently exempt account or workspace tries to start billing or redeem a coupon.

Fix: No checkout is necessary. Founder access already includes the Presence plan without an expiry.

A submitted internal trial coupon does not match the configured code.

Fix: Check the code and retry. Coupon values are case insensitive.

A coupon is submitted but no production coupon is configured.

Fix: Set INSTANCEOFAI_TEST_COUPON_CODE, or use TESTE30 only while CREEM_TEST_MODE is enabled.

An account tries to create another workspace while it already owns the maximum number of workspaces without a subscription.

Fix: Use an existing workspace, delete one that is no longer needed, or subscribe in one of them first.

The workspace tries to redeem the same trial coupon more than once.

Fix: Continue with the active trial or choose a paid plan when it ends.

A workspace with an active provider subscription tries to replace it with an internal trial.

Fix: Manage or cancel the subscription first, then contact support if a trial should be applied.

Meetings, uploads and transcripts

A non-owner tried to change meeting access, or a reader granted a private meeting tried to rename, reprocess, correct, add memory to or delete it.

Fix: Ask the meeting owner or workspace owner to make the change.

Meeting visibility or access recipients are invalid.

Fix: Choose workspace or private and existing workspace member or key identifiers.

Meeting date is invalid or has no time zone.

Fix: Use an ISO 8601 timestamp with Z or a numeric offset.

A correction contains invalid fields.

Fix: Check the field hints and submit a valid correction.

The meeting changed or is being processed while a correction was submitted.

Fix: Reload the meeting, keep your draft, and apply it to the latest version.

The meeting id does not exist (or was deleted).

Fix: GET /api/v1/meetings, or use list_meetings / recall to get valid ids.

Creating a meeting from JSON with no transcript and no file.

Fix: Send {"title":"...","transcript":"Alice: ..."} or a multipart body with {file}.

The transcript had no readable lines.

Fix: Send plain 'Speaker: text' lines, VTT, SRT, or JSON [{speaker,start_ms,end_ms,text}].

Reprocessing a meeting whose notetaker is still scheduled, in the call or leaving.

Fix: Wait for get_bot to report done or failed; the notes are produced automatically when the recording is saved.

Processing a meeting that has neither transcript nor transcribable audio.

Fix: Upload audio with DEEPGRAM_API_KEY or OPENAI_API_KEY configured, or send transcript text. GET /api/v1/setup shows provider status.

The uploaded file is neither audio/video nor a transcript.

Fix: Use mp3, m4a, wav, webm, mp4, ogg, flac — or txt, vtt, srt, json.

The upload exceeds INSTANCEOFAI_MAX_UPLOAD_MB (default 200).

Fix: Raise INSTANCEOFAI_MAX_UPLOAD_MB, or split the recording. Long calls transcribe fine; the limit is about memory, not duration.

A text transcript above 10 MB.

Fix: Split it into separate meetings — one per call.

The server volume is below its free-space floor, so a new recording or upload is refused rather than started and truncated.

Fix: Recordings already in progress finish normally. Free space on the host, raise the volume, or lower the workspace retention window, then retry. Operators: `node scripts/admin.mjs disk`.

no_audioHTTP 404

Requesting audio for a meeting with no recording (e.g. created from text).

Fix: Only bot recordings and uploads have audio. Check meeting.has_audio first.

no_videoHTTP 404

Requesting video that was not recorded.

Fix: Send the bot with {"video": true} (or INSTANCEOFAI_BOT_VIDEO=1) to record the call as video.

An endpoint that needs an AI provider (Ask, agent) with no OPENAI_API_KEY or Anthropic credential.

Fix: Add OPENAI_API_KEY or ANTHROPIC_API_KEY to your instanceofai env file and restart. Notes still work without one (heuristic), Ask does not. A human must supply this key — never invent one.

transcription_provider is not a configured provider.

Fix: Use "deepgram" or "openai", and only one that GET /api/v1/setup reports as configured.

Search without q.

Fix: GET /api/v1/search?q=your+terms

Ask without a question.

Fix: POST {"question":"..."}.

The translated notes change the number of items, task owners or dates.

Fix: The original notes and saved translation were preserved. Review the current notes before translating again.

no_recapHTTP 404

A translated recap was requested for a language that has not been generated.

Fix: POST /api/v1/meetings/{id}/recap {"language":"en"} (or get_recap with language) translates the notes; it needs an AI provider.

A recap language is missing, malformed or longer than 12 characters.

Fix: Use a BCP-47 code such as en, pt, pt-BR, es.

no_minutesHTTP 404

Minutes requested for a meeting that has no notes yet.

Fix: Wait for status=ready, then GET /api/v1/meetings/{id}/minutes again (or POST to regenerate).

no_analyticsHTTP 409

Coaching analytics requested for a meeting that is not ready yet or has no transcript lines.

Fix: Wait for status=ready (or send a transcript), then GET /api/v1/meetings/{id}/analytics again. POST the same path with {force:true} to recompute.

create_meeting_from_audio_url could not download the recording: the link answered an error.

Fix: Use a direct, public link to the file itself, not a page that shows it.

Memory (recall, facts)

close_commitment with an unknown fact id.

Fix: Fact ids come from recall and get_commitments.

forget was asked to take back a claim that was read from the meeting's notes, not added with remember.

Fix: Correct the notes with review_meeting (summary); the claim follows them.

update_commitment was asked to change a task that is not one of the meeting notes' action items.

Fix: Edit the notes with review_meeting instead.

empty_factHTTP 400

remember called with empty text.

Fix: Send {"meeting_id":"mtg_...","text":"the claim to remember"}.

recall or remember with a kind outside the fact kinds.

Fix: Use a comma separated subset of the kinds the message lists (commitment, decision, question, topic, point, note).

Follow-up queue

An automation field, action or destination is invalid.

Fix: Check the plan fields and choose a supported application.

The caller cannot access this automation or connection.

Fix: Sign in as its owner or use an explicitly authorized key.

The automation is absent or belongs to another actor.

Fix: List your own automation items.

The source, rule, approval or step state changed.

Fix: Read the current plan and review before continuing.

An app connection is missing or revoked.

Fix: Connect the app and verify the selected account.

A hosted automation dependency is not configured.

Fix: Configure the operator credentials or use your own external agent.

Telegram did not accept the bot token or its webhook when connecting a workspace's own bot.

Fix: Copy the token again from BotFather (/mybots, API Token) and paste the whole value. Your own bot needs the hosted workspace or a public HTTPS address.

The Telegram chat that pressed Start (or opened the claim link) is already connected to a different person. Each chat is one person's agent, so nothing was connected or moved.

Fix: The person the chat belongs to disconnects it first (/stop in the chat, or Disconnect in Apps). Otherwise connect your own Telegram account.

There is no Telegram chat waiting for your confirmation on this connection link: it expired, was used, was replaced by a newer link, or nobody pressed Start yet.

Fix: Open the link in Telegram and press Start, then confirm the account shown in the browser. Create a new link if fifteen minutes passed.

That Telegram bot is already connected to another workspace.

Fix: Disconnect it in the other workspace first, or create another bot with /newbot in BotFather.

complete_followup / cancel_followup with an unknown id.

Fix: Claim work with next_followup, or list_followups to see the queue.

complete_followup / cancel_followup on a job you do not hold: still queued, claimed by another agent (a claim older than 30 minutes is released and can be taken again), or already done, failed or cancelled.

Fix: Claim work with next_followup and report the outcome of that job. A finished job stays finished.

A rule whose instruction is too short to act on.

Fix: Describe the work in plain language: {"instruction":"Open a GitHub issue in acme/api for each action item assigned to me"}.

A status filter that is not queued, claimed, done, failed or cancelled.

Fix: Use one of those, or omit status to list everything.

A webhook with an invalid URL or body.

Fix: Send a public https URL and events from the listed set.

A webhook subscribed to no event or to an unknown one.

Fix: Pick at least one of the events the message lists.

Deleting or reading a webhook id that does not exist.

Fix: list_webhooks (GET /api/v1/webhooks) shows the ids.

Meeting bot

A configured participant account has no usable session.

Fix: Ask the operator to renew its browser session and mark the identity healthy, then send the notetaker again. Reconnecting the calendar does not renew this account.

The external capture worker is offline.

Fix: Start npm run worker:capture with the same workspace storage and environment.

A capture command failed or its outcome is uncertain after a restart.

Fix: Inspect bot status and logs before repeating an external message.

A capture command exceeded the HTTP wait time.

Fix: The command might still finish. Inspect the call before retrying.

Google Meet refused the notetaker before any person could admit it (the bot's error_code after a join attempt).

Fix: Ask the meeting host to allow guests from outside the organization, or to admit the notetaker when it asks to join, then send it again. If the meeting only admits signed in accounts, invite the notetaker's account to the event. Operators of a self managed deployment can give the notetaker a dedicated signed in account; that never overrides host or organization restrictions.

The link is not a recognised Zoom, Google Meet or Microsoft Teams invite.

Fix: Paste the full invite link (or the whole invite text). Other platforms are not supported — that is a deliberate scope choice, not a bug.

join_at is not a valid ISO-8601 time, or it is more than 15 minutes in the past (a wrong year or zone, never "join now").

Fix: Use {"join_at":"2026-09-04T15:00:00Z"}, or omit it to join now.

Chromium is missing on the instanceofai machine.

Fix: Run `npx instanceofai bot install` (or `npx playwright install chromium`) on that machine and restart the server.

Unknown bot id.

Fix: list_bots shows current ids.

Asking a finished or cancelled bot to leave.

Fix: Check get_bot → status first; done/failed/cancelled bots have already left.

A bot is already in that meeting link (details.bot_id).

Fix: Reuse that bot, or make it leave first. One bot per link is a hard rule — two bots in one call record each other.

INSTANCEOFAI_BOT_MAX_CONCURRENT (default 3) live bots already.

Fix: Wait, raise the limit, or schedule with join_at. Each bot is a full Chromium — the limit protects the machine.

Every recording slot on the service was busy for the 15 minutes after the notetaker was due, so it could not join. The operator is alerted.

Fix: Send the notetaker again if the meeting is still taking place. This is a capacity problem on our side, not a limit of your plan.

The plan's number of simultaneous notetakers was in use for the 15 minutes after this one was due.

Fix: Let one of the other calls finish (or make its notetaker leave), then send this one again. A plan with more simultaneous notetakers avoids it.

not_admittedHTTP 409

Nobody admitted the notetaker from the waiting room before the admission wait ran out (20 minutes by default, per calendar with admission_wait_min).

Fix: Ask the host to admit the notetaker when it asks to join, then send it again. On Google Meet, inviting the notetaker's account to the calendar event or setting the meeting access to Open lets it join without waiting. On Zoom, the host can turn off the waiting room for the meeting. On Microsoft Teams, the organizer can set who can bypass the lobby to Everyone in the meeting options.

A queued notetaker could not start within 15 minutes of its requested start time.

Fix: Check whether the meeting is still taking place before sending the notetaker again. Old links are never joined automatically after an outage.

No screenshot was captured for that bot.

Fix: Screenshots are written on failure and while waiting for admission; a bot that never got that far has none.

missing_urlHTTP 400

POST /api/v1/bots or /api/v1/calendars without `url`.

Fix: Bots: {"url":"<Zoom, Meet or Teams link>"}. Calendars: {"url":"<iCal/ICS address>"} copied by a human from the calendar's settings; never invent one.

Bot identity

Bot display name longer than 60 characters.

Fix: Shorten it — it has to fit a participant list.

Join message longer than 500 characters.

Fix: One or two sentences. '{name}' is replaced by the bot name.

The avatar is not a PNG/JPEG/WebP/GIF data URL.

Fix: Send {"avatar":"data:image/png;base64,..."} or {"avatar_url":"https://..."}; null removes it.

The avatar URL is not a fetchable public image.

Fix: Use a public http(s) image URL. Private-network URLs are refused unless INSTANCEOFAI_ALLOW_PRIVATE_NETWORK=1.

Avatar over 5 MB.

Fix: Resize it. The card is rendered at 1280×720 — anything above ~500 KB is wasted.

no_avatarHTTP 404

Requesting the avatar image when none is set.

Fix: Set one with configure_bot / PUT /api/v1/bots/identity; without it the bot shows an initials card.

Calendar auto-join

disconnect_calendar or update_calendar on the Bookings calendar, which mirrors every booking. Agents may set only its meeting profile and join offset.

Fix: Change notetaker and recap choices per event type in the booking settings (/booking), or per meeting with set_meeting_auto_join. The owner adjusts the rest at /meetings/setup#calendars.

The URL is not a usable https/webcal ICS address.

Fix: Use the calendar's secret iCal address (Google → Settings → the calendar → 'Secret address in iCal format'; Outlook → Publish → ICS). A human must supply it — never guess one.

The URL answered, but the body is not iCalendar data.

Fix: Check you copied the ICS link and not the calendar's web page. The body should start with BEGIN:VCALENDAR.

A native calendar write lacks provider consent or required safeguards.

Fix: Review provider consent and prepare an explicit event change.

A native write changed concurrently or its external result is uncertain.

Fix: Inspect the external event and reconcile the operation before a new write.

The calendar provider definitely refused a native event write, so nothing was written and the request key is free again.

Fix: Read the event again, correct the change and retry with the same or a new request key.

A calendar provider lacks server OAuth or encryption configuration.

Fix: Configure its client id, secret and INSTANCEOFAI_ENCRYPTION_KEY, register the callback URL and restart.

The provider refused OAuth or omitted offline identity.

Fix: Reconnect the calendar account and review provider consent.

The feed could not be read (network, auth, or the provider is down).

Fix: Open the URL in a browser to confirm it still works; secret addresses are revoked when a user resets them.

That feed is already connected (details.calendar_id).

Fix: Update the existing calendar instead (update_calendar / PATCH /api/v1/calendars/{id}).

Unknown calendar id.

Fix: list_calendars shows connected feeds.

Unknown calendar event id.

Fix: list_upcoming_meetings returns event_ids.

auto_join is not true, false or null.

Fix: true = always join, false = never, null = follow the calendar's rules.

A rule field is out of range (e.g. join_offset_min above 60).

Fix: Check the field ranges in the reference; the message names the offending field.

Delegate notes are not a string, or longer than 4000 characters.

Fix: PUT /api/v1/calendar/events/{id}/delegate {"notes":"..."} with plain text under 4000 characters, or {"notes":null} to clear them.

Calendar OAuth and recap email

The signed support email could not be retrieved or delivered to the configured operator Telegram chat.

Fix: Verify Resend receiving, webhook secret, API key, Telegram bot token and the operator chat ID. Retry the same signed event.

A calendar recap policy is not none, owner or attendees.

Fix: Choose none, owner, or attendees. Attendee delivery is one private message per non-declined invitee.

Google OAuth is opened before its client id, client secret or encryption key is configured.

Fix: Set GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET and INSTANCEOFAI_ENCRYPTION_KEY, register the exact callback URL, then restart.

Google rejects the code exchange or account lookup.

Fix: Verify the redirect URI, consent screen, Calendar API, test-user access and client credentials, then reconnect.

Google did not issue offline access.

Fix: Revoke instanceof.ai under Google third-party access, reconnect and approve consent.

An OAuth callback state is invalid, reused or older than that provider's short approval window.

Fix: Start a fresh connection from the matching app or calendar settings page.

A calendar references a removed OAuth connection.

Fix: Reconnect the Google account.

Google Calendar API cannot be read.

Fix: Retry sync; reconnect if the user revoked access.

A suppression request contains an invalid address.

Fix: Use a complete email address.

A recap/share/unsubscribe token is malformed or has an invalid signature.

Fix: Use the complete link from the recap email.

A signed email link is past its expiry.

Fix: Ask the meeting owner for a fresh summary.

The token is valid but its sent delivery or meeting summary no longer exists.

Fix: Ask the meeting owner for the summary.

An agent tried to answer a support email through the generic chat reply. Email leaves under the support address, so it goes through the email tool, which previews first and refuses a blocked sender.

Fix: Call reply_email_conversation with send=false to preview, then send=true.

The sender of this conversation is blocked, so it is not answered.

Fix: Unblock them in Conversations before replying.

Sending from the email inbox while outbound email is not configured on this deployment.

Fix: The operator configures SMTP. An agent cannot supply it; reply from another channel meanwhile.

An email reply may already have left (the SMTP result is unknown).

Fix: Do not send again. Check the Sent mailbox or the delivery status first.

Presence: voice, facilitation, avatar

Voice or facilitation needs a speech provider and none is configured.

Fix: Add DEEPGRAM_API_KEY (Aura voices) or OPENAI_API_KEY (tts) to the env file and restart. A human must supply the key.

say_in_meeting / post_in_meeting_chat for a bot that is not in a call, or that joined without presence.

Fix: The bot must be recording and its profile must enable the assistant (assistant.chat / assistant.voice). get_bot shows the status and metadata.presence.

An avatar pack is missing a required state, or a clip is not a webm/mp4 under 20 MB.

Fix: A pack needs at least idle; listening, speaking and nod fall back to idle. Clips: webm or mp4, 1280×720, 2 to 8 seconds, under 20 MB each.

Unknown avatar pack id.

Fix: list_avatar_packs shows the built-in packs (mark, portrait) and the uploaded ones.

configure_presence / PUT /api/v1/presence with an unknown voice, an over-long subtitle or owner name.

Fix: Voices: a Deepgram Aura 2 id (aura-2-thalia-en …) or an OpenAI voice (alloy, nova …) that your keys unlock; GET /api/v1/presence lists them. Subtitle ≤ 80 and owner_name ≤ 60 characters.

Illustrating the portrait pack when the bot has no photo.

Fix: Upload a photo first (PUT /api/v1/bots/identity {avatar} or the Bot identity panel), then POST /api/v1/presence/packs {"illustrate":true}.

Optional portrait generation has not been enabled after commercial review.

Fix: Use the existing photo or an uploaded avatar. Operators must complete the generation and moderation review before activation.

Portrait prompt screening failed, timed out or returned an unrecognized result.

Fix: No generation proceeds without an explicit matching allow. Retry later or use the photo.

Portrait prompt screening returned flag or deny.

Fix: Use the existing photo or a prepared avatar. No image generation was started.

OpenAI's image edit for the portrait illustration failed or returned nothing.

Fix: Retry later, or keep the photo: the portrait pack works without the illustration.

missing_textHTTP 400

say_in_meeting / post_in_meeting_chat / the preview with no text.

Fix: Send {"text":"..."} with the line to say or post.

Link page

The workspace has no link page or the requested page id is absent.

Fix: Create one with create_bio_page or POST /api/v1/bio.

An agent omitted page_id in a workspace with multiple Bio pages.

Fix: Call list_bio_pages and pass the intended page_id explicitly.

A workspace already has the maximum number of Bio profiles.

Fix: Delete an unused profile before creating another one.

A platform shortcut matched more than one social account.

Fix: Call get_bio_page and pass the exact social_id.

The selected social destination does not exist on that profile.

Fix: Call get_bio_page and use a current social_id.

A link page handle is reserved or belongs to another workspace.

Fix: Choose a different handle.

The domain is empty, an IP address, this product's own domain, or not a plain hostname. The same code is 409 when this deployment has no pages domain.

Fix: Send a hostname you control, such as agenda.example.com. An operator sets INSTANCEOFAI_PAGES_DOMAIN before any customer domain can answer.

That hostname is already attached to another page.

Fix: Remove it from the other page, or choose a different hostname.

A general page patch attempted to change the public handle.

Fix: Use change_bio_handle so the old address receives a protected redirect.

A public handle was changed less than seven days ago.

Fix: Wait until details.available_at before changing it again.

An analytics date range is invalid, reversed or longer than 365 days.

Fix: Use ISO 8601 from and to values covering no more than 365 days, or send days from 1 to 365.

A page field is missing, invalid or cannot be rendered accessibly.

Fix: Follow the returned field paths and call get_bio_capabilities for supported values.

An uploaded bio image is missing its file name or data URL, has an unsupported type, or exceeds 5 MB.

Fix: Send `name` (aliases: `filename`, `file_name`) and `data_url` as a PNG, JPEG, WebP or GIF base64 data URL under 5 MB.

An uploaded image id does not exist on this page.

Fix: Call list_bio_assets and use a current asset id.

A requested automatic snapshot does not exist for this page.

Fix: Call list_bio_revisions and use one of its ids.

A Bio profile changed after the caller read it.

Fix: Read the page again, merge the intended change and retry with current_revision as expected_revision.

A request_key (or its deprecated alias idempotency_key) was reused with different input, on a Bio tool or any create style tool.

Fix: Retry the original input or use a new request_key.

A requested block id does not exist on the page.

Fix: Call get_bio_page and use a current block id.

A requested product id does not exist in the catalogue.

Fix: Call get_bio_page and use a current product id.

Publishing was requested while readiness has blocking errors.

Fix: Call validate_bio_page, fix every error path, preview and publish again.

Booking page and the scheduling protocol

Freshness policy requires recent calendar synchronization before offering times.

Fix: Synchronize connected calendars and request fresh proposals.

An idempotency key was reused with different booking input.

Fix: Retain the same key and input for retries; generate a new key for a new request.

A new booking handle uses a dot or underscore while pages are served on subdomains.

Fix: Use 3 to 40 letters, digits and hyphens. A handle the page already has keeps working on its path address.

A google_meet booking location names a missing Meet connection, or one without meetings.space.created.

Fix: Use an id from get_google_app_connections (app=meet), or reconnect with request_google_app_connection and approve every permission.

retry_booking_conference was called for a booking without a Google Meet location.

Fix: Only google_meet bookings get a space; use update_booking_location to change one booking.

The workspace has no booking page yet, or the public handle does not exist / is unpublished.

Fix: Owner: create_booking_page {handle, name, timezone} (or POST /api/v1/booking). Visitor or agent: check the handle in the URL; GET /api/v1/book/{handle} lists what is bookable.

The handle is reserved or already used by another workspace.

Fix: Choose another handle. Handles are unique across every customer.

create_booking_page (or POST /api/v1/booking) in a workspace that already has its booking page.

Fix: One workspace has one booking page: read it with get_booking_page and change it with update_booking_page (the handle too).

Deleting an event type that still has upcoming bookings (details.upcoming): rescheduling and approving them need the type, so force does not override it.

Fix: Deactivate the type instead with update_booking_type {active:false} (it leaves the page, its bookings keep working), or cancel the upcoming bookings first.

Deleting a booking type, a booking page or a form that other apps still point at (details.dependents: link page buttons, booking routing rules, form booking routing), each with the fix_tool and fix_input that removes the reference.

Fix: Run each dependent's fix_tool, then delete again; or repeat the delete with force: true to leave them broken (the response lists them as broken_references).

Deleting a booking page that still has upcoming bookings (details.upcoming): their guests hold manage links and invites that depend on it.

Fix: Cancel the upcoming bookings first, or unpublish the page instead; guests keep managing their bookings either way.

Asking for proposals while too many times on the page are already held by the protocol (per requester, per day or in total).

Fix: Accept or decline the proposals you already hold, or wait for holds to expire (policy.hold_minutes) and ask again.

A page or event type field is missing, out of range or contradictory (a schedule interval that ends before it starts, a default duration not in durations, an unknown palette).

Fix: The message names the field. Times are HH:MM in the page's time zone; durations are minutes; weekdays are mon..sun.

update_booking_type (PATCH /api/v1/booking/types/{slug}) sent expected_updated_at and the event type changed after it was read.

Fix: Read the event type again, merge the intended change and retry with its current updated_at as expected_updated_at. Omit the field to merge without the check.

No event type with that slug (or it is inactive / hidden to the public).

Fix: list_booking_types shows the slugs; the public manifest GET /api/v1/book/{handle} lists the bookable ones.

A time zone that is not an IANA name.

Fix: Use names like America/Sao_Paulo, Europe/Lisbon, UTC.

starts_at is not an ISO-8601 instant, is in the past, or is not aligned to the type's slot interval.

Fix: Ask for slots (GET .../slots or POST .../request) and send one of the returned starts_at values verbatim.

The requested time is outside the hours, inside a buffer, already booked, held by somebody else, or over the daily / weekly limit.

Fix: details.reason says which. Request a fresh proposal: POST /api/v1/book/{handle}/{type}/request, or GET .../slots and pick another.

Unknown booking id, or a manage token that does not match it.

Fix: list_bookings shows ids; invitees use the link from their confirmation email.

approve_booking / decline on a booking that is not awaiting approval.

Fix: Only status=pending bookings can be approved or declined. cancel_booking works on confirmed ones.

Cancelling or rescheduling a booking that is already cancelled, rescheduled or in the past.

Fix: Create a new booking instead.

A manage or single-use link token is malformed or has a bad signature.

Fix: Use the complete link from the email or from create_booking_link.

Unknown negotiation id.

Fix: POST /api/v1/book/{handle}/{type}/request starts one; its id is in the response.

counter / accept / decline on a negotiation that is already booked, declined or exhausted, or on a proposal whose hold expired.

Fix: Start a new request. Holds last policy.hold_minutes (default 15); accept within that window.

No slot satisfies the constraints inside the type's hours and range (details.searched says the window and what was busy).

Fix: Loosen the constraints (a wider window, other weekdays, a shorter duration) or ask the owner for a one-off link with extra hours.

Unknown meeting poll id.

Fix: list_booking_polls shows the open ones.

poll_closedHTTP 409

Voting on or closing a poll that is already closed.

Fix: The booking it produced is in booking_id.

invalid_pollHTTP 400

A poll with no options, a vote for an unknown option, or a vote with no name.

Fix: Options are ISO-8601 starts; votes carry {name, email?, option_ids}.

A host id that is not on the page (collective / round robin types, or host_id on a booking).

Fix: update_booking_page {patch:{hosts:[{id, name, email, calendar_ids}]}} adds hosts; "owner" is always the page owner.

Approving a booking whose type requires payment before the invitee paid.

Fix: mark_booking_paid {booking_id} once the payment arrived through your own checkout link; the booking confirms by itself.

An email handed to the scheduling assistant has no sender or no text.

Fix: Send {from:{email,name}, subject, text, message_id?, in_reply_to?} or the raw payload of a Postmark, SendGrid or Mailgun inbound webhook.

The public inbound address received an email but the page's assistant is off, or the inbound token is wrong.

Fix: update_booking_page {patch:{assistant:{enabled:true}}} and use the inbound URL with its token from get_booking_page.

Routines, Instagram and WhatsApp

The owner paused automatic replies on this account, or the message predates the last resume.

Fix: Review the account in the social workspace. Resuming only permits new incoming messages under existing grants.

An agent tried to let a routine act alone, decide a draft, approve an automation plan or integration grant, activate a campaign or connect a social account. Only the person does that.

Fix: Send the owner the review_url (or rely on the Telegram card from propose_routine / request_routine_autonomy) and poll get_routine_proposal.

The routine id does not belong to the person this credential speaks for.

Fix: Call explain_routines and use one of its ids.

A routine names an unknown signal or action, tests a field the signal does not have, or sends a message without its text.

Fix: Call list_routine_catalog for the signals, fields and actions; give action.text (it may use {{field}}) or ask the owner for it.

A draft or a button was tapped after what it was about changed (someone already answered, the review changed, the booking moved, the item is gone): nothing was sent.

Fix: Read the resource again and act on its current state; list_routine_runs shows the run as skipped.

The default routine sends a message the owner has to write first (the link a comment keyword sends), and it was switched on before that.

Fix: Ask the owner for the message and the link, call update_routine with action.text, then turn the routine on.

The routine has no authorization to renew: it was never authorized, the owner revoked it, or the routine changed since.

Fix: The owner authorizes it again at /agents/routines (only a person can).

A routine's Remind tapped when every overdue task already has a reminder waiting, was reminded in the last 24 hours, or belongs to someone who opted out of our email: nothing new was queued.

Fix: Nothing to do; list_nudges shows the reminders already waiting and next_followup hands them to your agent.

The person already has 100 custom routines.

Fix: Remove one with remove_routine, or change an existing one.

The plan_hash does not match what is prepared now: the proposal, the routine or the draft changed.

Fix: Read the proposal or the run again and use its current plan_hash.

The proposal does not exist for this person.

Fix: Call propose_routine again.

The proposal was already activated, cancelled or expired (24 hours).

Fix: Call propose_routine again if the person still wants it.

The notice no longer exists (older than 90 days) or belongs to someone else.

Fix: Open /agents/routines#activity.

The notice was already decided, expired (7 days) or dropped because its routine changed.

Fix: Nothing to do; a new event prepares a new draft.

An action names a tool the registry no longer has.

Fix: Update the action catalogue in src/lib/routines/actions.ts.

Another routine decision reserved this action for the same event and has not returned a confirmed result. The waiting draft remains unchanged.

Fix: Review routine activity; wait for the admitted decision. Never resubmit or retry automatically.

An earlier execution of the same event/action is uncertain or partially applied. This draft cannot repeat its effects.

Fix: Review routine activity and the source/provider state. Expiration, editing the draft or dismissing a notice does not free the execution key.

An admitted execution could not confirm its own reservation after returning from a tool. Its effects must be reviewed.

Fix: Inspect the original run and actual effect; never repeat the action to compensate for a missing acknowledgement.

The deployment does not receive Meta events: META_APP_SECRET or META_WEBHOOK_VERIFY_TOKEN is missing, or the event could not be stored.

Fix: The operator sets both and subscribes the Meta app to /api/v1/social/webhook. Meta retries failed deliveries.

A social account was connected on a deployment without INSTANCEOFAI_ENCRYPTION_KEY.

Fix: The operator sets the key; the token is never stored in clear.

The Instagram account or WhatsApp number is connected to another workspace.

Fix: Disconnect it there first.

The account behind a stored message is no longer connected.

Fix: The owner reconnects it at /agents/routines#social.

Meta no longer allows a reply: 24 hours after the person's last message (7 days for a private reply to a comment, or for a person answering an Instagram DM). WhatsApp has no seven day extension.

Fix: On Instagram, answer from the app. On WhatsApp only an approved message template can reach the person after 24 hours.

The thread has no author to block (a mention carries none).

Fix: Hide the post or the mention in the app instead.

A triage lesson id that does not exist (already forgotten).

Fix: Call list_triage_lessons and use an id it returns.

A ready answer id that does not exist (deleted, or from another workspace).

Fix: Call list_ready_answers and use an id it returns.

The workspace already keeps 200 ready answers.

Fix: Delete or merge answers that repeat each other before adding another.

The conversation's latest message has no triage reading (it arrived before triage, or its message is gone).

Fix: Read the conversation itself; triage applies to messages that arrive from now on.

This request_key belongs to a reply that is still pending or waiting for a human check.

Fix: Check the conversation in the app and call resolve_social_reply; never send it again blindly.

Meta did not confirm the reply; it may have been sent.

Fix: Check the conversation, then resolve_social_reply with sent=true or false. The reply is never repeated automatically.

Something automatic (a routine, a campaign, an agent) tried to write to a person who asked not to be contacted.

Fix: Nothing was sent. Only a person may still answer them, from Conversas; the owner lifts the request if the person asks to start again.

Meta refused the reply (a definite 4xx): nothing was sent.

Fix: Fix the text or the connection and retry with the same request_key.

An Instagram or WhatsApp action while no account is connected.

Fix: The owner connects one in Conversations, Configure (/inbox/setup).

More than one account of that network is connected and none was named.

Fix: Pass connection_id (details.connections lists them).

Reconnecting a connection with a different Instagram account.

Fix: Connect the same account, or add the other one as a new connection.

The Instagram app is not configured on this deployment.

Fix: The operator configures the Meta app. An agent cannot supply it.

The Instagram connection link expired or was already used.

Fix: Start the connection again from Conversations, Configure.

Instagram (or the bridge) did not accept the authorization or did not identify the account.

Fix: Start again with an Instagram professional account; finish the provider page before returning.

The Instagram bridge is not configured, needs its identity verifier, or refused an action outside its allowlist.

Fix: The operator configures the bridge. Use the direct connection when it is available.

The action needs the direct Meta connection (a DM to someone who only commented, quick reply buttons, an answer after 24 hours) and the account uses the bridge.

Fix: Reply in public asking for a DM, or switch the account to the direct connection in Conversations, Configure.

The owner switched this action off for the connected account (messages, comments, publishing, deleting comments or metrics).

Fix: Only the owner turns it back on, in Conversations › Configure, on the account. Do not ask again unless the person wants it.

An automatic reply found the message already answered after it arrived (by you in the app or Conversas, or by another automatic reply): nothing was sent.

Fix: Nothing to do; the conversation is in Conversas if it needs more.

The comment already received its one private reply.

Fix: Meta allows one per comment. Continue in the DM once the person answers.

A reply was refused by the session guard (Meta's window closed, a loose link, a claim outside the facts, a reserved topic).

Fix: Rephrase within the playbook's facts, use an offer link, or let the owner answer from the Instagram app.

Answering in a campaign conversation that has already ended.

Fix: Answer from the Instagram app, or through Conversations as the person.

The my_agent turn lease expired or belongs to another receipt.

Fix: Do not send the stale reply. Call next_social_turn again.

A campaign offer has no published form, bookable type or destination.

Fix: Complete the offer (a published form, an active booking type, a published page) before the campaign runs.

The workspace already has 100 campaigns.

Fix: Archive one before creating another.

External integrations

A publishing video has an unsupported size, container or codec, or could not be inspected.

Fix: Upload a supported video and ensure ffprobe is installed.

Reserved and stored media exceed the workspace quota.

Fix: Delete unused media before starting another upload.

Upload offset, state or expiry changed.

Fix: Read get_publishing_media and resume from its acknowledged offset.

An active publication still needs this file.

Fix: Cancel queued work or wait for active transfers to finish.

A delivery may have succeeded without confirmation.

Fix: Inspect the existing delivery. Never submit it under a new key without reconciliation.

The action reads, writes, sends or deletes, and the owner unticked that effect for this connected account when connecting it or later.

Fix: Tell the person what you need and why; they can allow it on the account in Settings, Apps. Do not switch to another account without asking.

The action name is not offered for the account's app on this deployment (a typo, another app's action, or one the operator excluded).

Fix: Find the exact action with search_app_actions and use its tool name.

The app is installed but this deployment does not offer what the tool runs on (no released, configured lane and no connected account), for example a work tool shared by Slack, Notion and Google.

Fix: Do not ask for the install again. list_apps shows the app with state unavailable_on_deployment; tell the person it is not available here yet.

A social provider does not return valid analytics.

Fix: Check the connection and optional analytics permissions, then retry the read later. No publication is sent.

Instagram refused its metrics: the connection was made without Meta's insights permission (instagram_business_manage_insights), on our Meta app or on the bridge's Composio auth config.

Fix: The owner reconnects the Instagram account and approves the metrics permission. On the bridge, the operator first adds that scope to the Composio auth config. Followers and post counters may still be shown.

Instagram answers metrics only for Business or Creator accounts, and the connected account is personal.

Fix: The owner switches the account to Professional in the Instagram app (Settings, Account type), then reads again. No reconnection is needed.

The network or the bridge rejected the stored authorization of this account (expired, revoked or removed at the provider).

Fix: The owner reconnects the same account from its app page. Nothing else changes.

The Composio bridge refused a read its configuration does not allow (the auth config, the pinned toolkit version or the operator's exclusion list).

Fix: The operator enables the read on the bridge (see docs/social-publishing.md, Analytics). Use the direct connection when it is available.

YouTube OAuth is opened before its client id, client secret or encryption key is configured.

Fix: Set YOUTUBE_CLIENT_ID, YOUTUBE_CLIENT_SECRET and INSTANCEOFAI_ENCRYPTION_KEY, register the exact callback URL, then restart.

Google rejects the YouTube OAuth exchange or account lookup.

Fix: Verify the redirect URI, consent screen, YouTube API, test-user access and client credentials, then reconnect.

Google did not issue offline YouTube access.

Fix: Revoke instanceof.ai under Google third-party access, reconnect and approve consent.

A YouTube operation references a removed connection.

Fix: Connect the YouTube account again.

The connected Google account has no usable YouTube channel.

Fix: Create or select a YouTube channel and reconnect.

YouTube did not return the requested video.

Fix: Check the video id and connected account.

YouTube rejected a read request or was unavailable.

Fix: Reconnect if access was revoked; otherwise retry.

YouTube could not create a resumable upload session, or a meeting recording upload was interrupted or answered 5xx.

Fix: For a session, retry once, then reconnect and check upload permission. For an interrupted recording upload, call reconcile_google_app_operation; never repeat it.

A live YouTube upload was requested without an owner certification that the exact video complies with the YouTube Community Guidelines.

Fix: Review the exact video and metadata with its owner, then set community_guidelines_certified to true before confirming the upload.

The stored YouTube grant lacks the access this call needs (for example analytics on an older connection).

Fix: Call request_youtube_connection again and have the owner approve.

Invalid date, end before start, more than 366 days, video_id with dimension=video, or top videos without a sortable metric.

Fix: Fix the dates; include views or estimatedMinutesWatched for top videos.

The channel has no recent public or unlisted, processed, embeddable upload.

Fix: Publish a public or unlisted video with embedding allowed and wait for processing.

block_id points to a bio block that is not an embed.

Fix: Pass an embed block id, or omit block_id to use the youtube-latest block.

The meeting has no video file (audio only).

Fix: Record with video: true.

privacy=public was requested for a private meeting.

Fix: Use private or unlisted, or change the meeting's access first.

The recording is empty, over 16 GB, or the meeting is over 12 hours.

Fix: Trim it outside the product and use create_youtube_upload_session.

The upload session never opened, so no bytes were sent and the request_key is free.

Fix: Retry with the same request_key; reconnect if it repeats.

YouTube answered 4xx after receiving the bytes (quota, metadata, channel limits).

Fix: Fix the reported cause and retry with a new request_key.

LinkedIn OAuth is opened before its client id, client secret or encryption key is configured.

Fix: Set LINKEDIN_CLIENT_ID, LINKEDIN_CLIENT_SECRET and INSTANCEOFAI_ENCRYPTION_KEY, register the exact callback URL, then restart.

LinkedIn rejects the authorization-code exchange.

Fix: Verify the HTTPS redirect URI, enabled OpenID and Share products, client credentials and then reconnect.

A LinkedIn operation references a removed connection.

Fix: Connect the LinkedIn account again.

The encrypted LinkedIn token envelope cannot be decrypted or parsed.

Fix: Disconnect the account and connect it again. Never paste a token into a request.

The standard LinkedIn access token reached its expiry time.

Fix: Reconnect LinkedIn. Programmatic refresh is limited to approved LinkedIn partners.

The stored LinkedIn grant lacks profile or member-post access.

Fix: Enable the matching LinkedIn product, then reconnect and approve the requested permissions.

LinkedIn rejects a profile read or is unavailable.

Fix: Reconnect after 401; otherwise retry later.

A LinkedIn request_key is reused for different text or visibility.

Fix: Use a new request_key for changed content.

The LinkedIn post may have reached the provider but no definitive result came back.

Fix: Check the member's LinkedIn activity before doing anything else. Never blindly repeat it.

A LinkedIn account connected through the bridge administers no company page. Analytics exist only for organization pages; a personal profile has none here.

Fix: The owner connects a LinkedIn account that is an administrator of the company page, from /apps/linkedin.

LinkedIn refused the page read: the connection was made without page administration access (r_organization_admin, rw_organization_admin), or the member is not an administrator of that page.

Fix: The owner reconnects LinkedIn from /apps/linkedin and approves page administration access. On the bridge, the operator first adds those scopes to the Composio auth config.

Page analytics were asked of the direct LinkedIn connection, which only has member posting scopes.

Fix: Connect the LinkedIn account through the bridge with page administration access, then read the page entry from get_social_analytics_accounts.

LinkedIn definitively rejects a text post.

Fix: Fix the provider-reported cause, review again and use a new request_key.

TikTok OAuth is opened before its client key, client secret or encryption key is configured.

Fix: Set TIKTOK_CLIENT_KEY, TIKTOK_CLIENT_SECRET and INSTANCEOFAI_ENCRYPTION_KEY, register the exact callback URL, then restart.

TikTok rejects the authorization-code or refresh-token exchange.

Fix: Verify the exact HTTPS redirect URI, Login Kit configuration and client credentials, then reconnect.

A TikTok operation references a removed connection.

Fix: Connect the TikTok account again.

The encrypted TikTok token envelope cannot be decrypted or parsed.

Fix: Disconnect the account and connect it again. Never paste a token into a request.

The saved TikTok grant lacks video.upload.

Fix: Reconnect TikTok after enabling Content Posting API and approve the requested permission.

A TikTok request_key is reused for a different video URL.

Fix: Use a new request_key for changed video content.

TikTok may have received the draft-upload request but did not confirm it.

Fix: Check TikTok drafts before trying again. Never blindly repeat an uncertain request.

TikTok definitively rejects a draft-upload request.

Fix: Fix the provider-reported cause, including a verified public HTTPS video URL, review again and use a new request_key.

A Google app connection names an app other than meet, business, drive or gmail.

Fix: Use app=meet, business, drive or gmail.

A connection was started through a way in that is not open to customers yet (details.connector, details.lane): the provider has not approved it or it has not passed a real end to end test. Configured credentials alone never open one.

Fix: Do not retry. Tell the owner it will appear in Apps once the provider approves it, and use what list_connections reports as available meanwhile. Nothing was sent to the provider.

Google Calendar, another Google app or YouTube is used before the operator turned it on. Credentials alone never enable an app.

Fix: Wait for the operator. They add the app to INSTANCEOFAI_GOOGLE_APPS (calendar, meet, business, drive, gmail, youtube or all) once its Google Cloud client, consent screen and verification are finished, then restart.

A Google app connection is opened before its OAuth client or the encryption key is configured.

Fix: Set GOOGLE_APPS_CLIENT_ID and GOOGLE_APPS_CLIENT_SECRET (or GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET) plus INSTANCEOFAI_ENCRYPTION_KEY, register /api/v1/integrations/google-apps/callback, then restart.

Google rejects a Google app code exchange, token refresh or account lookup.

Fix: Call request_google_app_connection for the app and have the owner approve it again.

Google did not issue offline access for a Google app.

Fix: Remove instanceof.ai under Google third-party access, reconnect and approve consent.

A Google app operation names a connection that was removed or belongs to another app.

Fix: get_google_app_connections lists the connections of each app.

The stored Google grant lacks a provider permission the operation needs.

Fix: Call request_google_app_connection for the app and have the owner approve every requested permission.

A Google app API refused a request or was unavailable. details carry provider_status and provider_reason.

Fix: Follow the hint: reconnect after 401, ask the operator about project access after 403, wait after 429, reconcile a write after 5xx.

A Google account already connected directly is connected again through the bridge.

Fix: Keep the direct connection. Disconnect it first only if the account really has to go back to the bridge.

A Google app is connected through the bridge before the operator configured it, or the app is one the bridge cannot carry (Business Profile, YouTube).

Fix: Wait for the operator. They add the app to INSTANCEOFAI_GOOGLE_BRIDGE with its provider auth config and scopes; Business Profile and YouTube wait for Google's own approval.

The bridge did not answer, answered an error or did not say what Google answered. Its own message is never quoted, because it may carry credentials.

Fix: Retry a read. Reconcile a write with reconcile_google_app_operation before repeating it.

An operation that needs a file upload or an endpoint outside the app's allowlist runs on a bridge connection. Nothing was sent.

Fix: Use the direct connection for this operation once Google approves it, or run it from an account connected directly.

The bridge connection was finished before the account became active at the provider.

Fix: Finish the connection on the provider's page, then call the callback again.

The provider's verification page was opened more than ten minutes after the connection started, the session was already used, or this person has no connection waiting. details.restart names the page to start again.

Fix: Start the connection again from the page that offered it and finish it within ten minutes.

The provider refused to complete the session for the person signed in: the connection belongs to another account, and the provider marked it failed.

Fix: Sign in as the person who started the connection and start it again (details.restart).

The same connection is already being confirmed, for example from a second tab. The provider session is completed only once.

Fix: Wait a moment, then open the page that offered the connection to see its state.

The provider did not answer the confirmation, answered a server error, or (503) connections are not configured on this server.

Fix: Start the connection again from the page that offered it (details.restart). The operator configures COMPOSIO_API_KEY when the status is 503.

A bridge connection did not return the Google account address, so it could not be upgraded to a direct connection later.

Fix: The operator adds the email and openid scopes to that app's auth config; then the owner connects again.

Google did not find the location, file, conference or message named in the request.

Fix: List the resource again and use an id from the result.

A Google write has a request_key outside 16 to 100 letters, digits, _ or -.

Fix: Send a random request_key and reuse it only to retry the identical operation.

A request_key was reused for a different Google write.

Fix: Use a new request_key for a new change.

A Google write is pending or its outcome is unknown.

Fix: Call reconcile_google_app_operation with the request_id. Never repeat an uncertain write.

conference_record or transcript is malformed, or the transcript belongs to another call.

Fix: Use names returned by list_google_meet_conferences and get_google_meet_conference.

since is later than until.

Fix: Swap or correct the dates.

The transcript is still being recorded, or the call has no FILE_GENERATED transcript.

Fix: Wait for FILE_GENERATED, or pass an ENDED transcript explicitly.

Google returned no transcript lines on a live import.

Fix: Retry later; lines can appear after the call ends.

A Business Profile reviews or posts call is refused because Google has not approved API access for this Cloud project.

Fix: The operator requests Business Profile API access (developers.google.com/my-business/content/prereqs). Locations and special hours keep working meanwhile.

A review reply is over 4096 UTF-8 bytes.

Fix: Shorten the reply to 4096 UTF-8 bytes or fewer and send it again.

A post button is CALL with a url, another type without a url, or the url is not http(s).

Fix: Fix call_to_action: CALL takes no url, every other type needs an https url.

A routine's reply to a Google review found the review already answered (by the owner or anyone else): nothing was written and the existing reply was kept.

Fix: Nothing to do; edit the existing reply yourself in Business Profile if it should change.

The review's rating changed after the reply was prepared (the reviewer edited it): nothing was written.

Fix: Read the review again; a review now at 3 stars or fewer arrives as its own notice for you to answer personally.

Before a routine's review reply, the current review could not be read, so nothing was written.

Fix: Try again later; the reply is not sent until the review can be checked.

The booking page has no away period, or it has already ended.

Fix: Set one with set_booking_away, then sync again.

The away period is longer than 60 days from today.

Fix: Shorten it, or mark the location temporarily closed in Business Profile.

The location has no regular hours, so Google refuses special hours.

Fix: The owner sets regular hours on the Business Profile first.

Another live run of the same sheet sync holds its lease.

Fix: Wait up to 2 minutes and run again. Nothing is duplicated.

Unknown sync_id.

Fix: Use an id from list_google_sheet_syncs.

A sheet sync names a form with no published revision.

Fix: Call publish_form, then create the sync.

The meeting markdown for a Google Doc export is over 10 MB.

Fix: Retry with include_transcript=false.

Gmail scheduling preview or processing runs on a connection with no label chosen.

Fix: Call list_gmail_labels, then set_gmail_scheduling_label with dry_run=false.

The chosen Gmail label is a system label such as INBOX or SENT.

Fix: Create a user label (for example Scheduling), optionally with a Gmail filter, and choose that one.

The transcript was already imported into a meeting the caller cannot read.

Fix: Ask the meeting owner or a workspace owner to share it.

WhatsApp did not return a message's attachment, or the connection cannot fetch media (it is not a direct Cloud API number).

Fix: Try again in a moment, or open it in the WhatsApp app.

WhatsApp no longer keeps this attachment (Meta keeps media for a limited time).

Fix: Ask the customer to send it again.

The attachment is larger than 25 MB.

Fix: Open it in the WhatsApp app.

A hosted agent seat has no runtime, or the gateway does not serve its profile yet.

Fix: Call provision_hosted_runtime for the seat, then retry.

The hosted agent runtime is not configured on this deployment or did not answer.

Fix: Retry in a moment. If it persists the operator checks the agents service; an agent cannot configure it.

CRM: people, pipelines and deals

A terminal merge decision lost its retained references through erasure or audit expiry.

Fix: Keep the original request key fenced. Read the current profiles and explicitly review a new decision; never reclaim the old key.

Current member addresses could not be checked before observing an identity.

Fix: Retry after workspace membership is available. The observer creates no person while this verification is unavailable.

A member profile mapping does not exist in this workspace.

Fix: List member profiles and use a current mapping id.

A relationship is absent or outside the reader's audience and scopes.

Fix: List accessible person relationships and use an id from that list.

The offer destination changed after the dashboard read it.

Fix: Read its current destination and explicitly choose the change again.

bind_offer_to_pipeline named a booking type, form or campaign that does not exist.

Fix: List booking types, forms or campaigns and pass an id they return.

A person id that does not exist or was erased.

Fix: Call search_people or identify_person and use an id it returns.

A company id that does not exist (or was deleted).

Fix: Call list_companies and use an id it returns.

Another company already has this domain.

Fix: Link people to it (details.company_id), or merge the two companies.

The domain is a free mail provider (gmail.com, outlook.com…), which says nothing about a company.

Fix: Leave the domain empty or use the company's own domain.

The person is already the deal's primary.

Fix: Add someone else, or open a deal for them.

The person holds no role on that deal.

Fix: Call get_deal_people for who is on it.

A pipeline cannot go back to one open deal per person while someone holds several there.

Fix: Close or move the extra deals, then save the pipeline again (details.people).

The two ids are already the same person.

Fix: Nothing to do: use the person id get_person returns for either one.

A merge id that does not exist.

Fix: Undo is available for 30 days after a merge; use the merge_id the merge returned.

A reading id that does not exist (or was erased with its person).

Fix: Use a reading id from list_deal_readings or the deal.signal event.

The reading was stored in shadow mode, so it may not be carried out.

Fix: Only readings taken with the reading on are applied; wait for the next message.

tag_existsHTTP 409

suggest_tag named a tag already in the vocabulary.

Fix: Use the tag; readings apply vocabulary tags by themselves.

merge_undoneHTTP 409

The merge was already undone.

Fix: Nothing to do: the two people are separate again and the pair is kept apart.

Undo was asked more than 30 days after the merge.

Fix: Keep the merged person and edit its details instead.

A mirror id that does not exist here, or another owner's.

Fix: Call list_crm_mirrors and use an id it returns.

A mirror run id that does not exist here, or another owner's.

Fix: Call list_crm_mirror_runs and use an id it returns.

The HubSpot, Pipedrive or RD Station account named is not connected by this owner.

Fix: Connect it on the app's page, then pass its id from get_app_integrations.

The pair is not waiting for a decision (decided or gone).

Fix: Call list_merge_candidates for the open pairs.

A person already decided these two are different people.

Fix: Do not propose the pair again unless something new links them; tell the owner what you found.

A task changed after the caller read it.

Fix: Read the task again and review its current revision before saving.

A task is maintained by its source meeting or process.

Fix: Update the original source through its own operation so all projections stay consistent.

A task id that does not exist (or was erased with its person).

Fix: Call list_deal_tasks and use an id it returns.

A task that is already done, replaced or cancelled was completed again.

Fix: List the deal's open tasks with list_deal_tasks.

An agent tried to write a person's note.

Fix: Record what you learned with record_person_fact; the owner approves it.

A pipeline id that does not exist.

Fix: Call list_pipelines and use an id it returns.

A stage id that does not exist.

Fix: Call get_pipeline and use one of its stage ids.

The stage belongs to another pipeline than the deal's.

Fix: Call get_pipeline for the deal's pipeline and use one of its stages.

stage_in_useHTTP 409

A stage that still holds deals was removed from a pipeline.

Fix: Move its deals to another stage first (details.deals says how many), then remove it.

The only pipeline was archived.

Fix: Create another pipeline first.

A deal was opened in an archived pipeline.

Fix: Use another pipeline or restore this one.

A deal id that does not exist.

Fix: Call list_deals or get_crm_board and use an id it returns.

The deal or its pipeline changed after the move was reviewed.

Fix: Read the current deal and pipeline, review them, then submit the new revision. Never automatically repeat an unconfirmed move.

deal_existsHTTP 409

The person already has an open deal in that pipeline (one per person per pipeline).

Fix: Move that deal instead: details.deal_id names it.

A deal was moved into a lost stage without a reason, or opened lost.

Fix: Pass lost_reason, one of the pipeline's lost_reasons (details.lost_reasons).

deal_closedHTTP 409

A next step was set on a deal that is already won or lost.

Fix: Move the deal back to an open stage first, or leave it closed.

schedule_deal_recheck was called without a reason.

Fix: Say why you will look again; the reason is shown to the owner.

human_onlyHTTP 403

An API key called something only a signed in person does (merge, erase, change a pipeline, decide a learning).

Fix: Ask the owner to do it in the dashboard, or propose it with the matching tool.

Knowledge and learnings

A learning id that does not exist.

Fix: Call list_learnings and use an id it returns.

A learning not scoped to one person carries an address, a phone or a document number.

Fix: Scope it to the person (person:<id>) or write it without the personal data.

An agent proposed a learning without saying why.

Fix: Pass why: what you saw that makes it worth keeping.

A retired learning was approved or published.

Fix: Review the current version and restore the learning before editing.

A knowledge decision used an older revision.

Fix: Read get_learning again and review the current text and sources before deciding with expected_revision.

A fact about one person was published to the customer chat.

Fix: Keep it approved; the attendant sees it only in that person's conversation.

Outbound requests

An outbound URL (webhook, calendar, avatar) resolves to a private or reserved address.

Fix: Use a public URL. INSTANCEOFAI_ALLOW_PRIVATE_NETWORK=1 relaxes private and loopback addresses for an isolated development deployment; instance metadata and link local addresses (169.254.0.0/16, fe80::/10, metadata.google.internal) are refused regardless.

The hostname does not resolve.

Fix: Check the spelling and that the host is reachable from the instanceofai machine.

The remote host refused, timed out or dropped the connection.

Fix: Retry; the error message carries the underlying cause.

A remote response exceeded the read limit.

Fix: Point instanceofai at a smaller resource — feeds and avatars are capped on purpose.

More than 3 redirects.

Fix: Use the final URL directly.

Request handling

The request body did not finish within its reception deadline.

Fix: Complete ordinary request bodies within 60 seconds and recording uploads within 15 minutes. Check operation state before retrying a mutation.

The client interrupted request reception.

Fix: Check operation state before retrying. Reuse the same idempotency key where supported.

An API or MCP request exceeds its byte limit.

Fix: Reduce the request size. Use the meeting upload endpoint for large transcripts or recordings.

Operation revision, references or request key changed.

Fix: Inspect the operation again and use its current review token. Reuse the original input for retries.

A tool call or suite operation contains invalid fields, or a top-level field the schema does not know (agent surfaces reject unknown fields instead of ignoring them).

Fix: Correct details.issues and repeat the same operation with the exact field names from the tool's input schema.

Another process held the workspace or control database lock longer than the web process waits (a short wait keeps one tenant's lock from freezing every other tenant). The failed statement changed nothing.

Fix: Repeat the same call after the Retry-After header's seconds; reuse the idempotency key if you sent one.

A call with this request_key is still running.

Fix: Wait a few seconds and retry with the same request_key and input; the first call's result comes back once it finishes.

invalid_jsonHTTP 400

The body is not valid JSON.

Fix: Send `Content-Type: application/json` and a JSON object.

missing_bodyHTTP 400

A required body was empty.

Fix: The message names the required fields.

A multipart upload could not be parsed.

Fix: Send a well-formed multipart/form-data body with a `file` part.

missing_fileHTTP 400

A multipart upload with no file part, or a server path given to create_meeting_from_audio_path that does not exist.

Fix: Name the part `file`, or pass a path the instanceofai server process can read.

refusedHTTP 422

The agent declined to answer (e.g. no grounding in the transcripts).

Fix: Rephrase, or check the workspace actually has the meetings you are asking about.

not_foundHTTP 404

The resource named in the request does not exist or is not visible to this caller, or the /api/v1 path itself is not a route.

Fix: Use an id returned by the matching list call. For an unknown path, check /openapi.json for the routes that exist.

rate_limitedHTTP 429

Too many requests or concurrent tool calls from this credential, address or runtime within the window.

Fix: Wait for the time the hint names (or for pending calls to finish) and retry once. Do not loop.

An irreversible action was sent without the confirmation field it requires (the exact name or id to type).

Fix: Resend with the confirmation value the message names (details.expected when given).

Ask received more than 100 messages, more than 200,000 characters, or a message without a role and content.

Fix: Send {"question":"..."} or {"messages":[{"role":"user","content":"..."}]} within the limits.

A multipart upload carried more form fields than allowed.

Fix: Send only the documented fields plus one `file` part.

A multipart upload carried more than one file.

Fix: Upload exactly one `file` part per request.

A multipart upload carried more parts than allowed.

Fix: Send only the documented fields plus one `file` part.

An unhandled error.

Fix: Check the server log (`npx instanceofai logs`) and GET /api/v1/setup for provider status. If it is reproducible, it is a bug — please report it with the log line.

Machine-readable reference: /llms-full.txt · /openapi.json