Blank pane, missing button, 'this page couldn't load', 502 on project lists — what each failure actually means and how to tell them apart.
Every entry here is a failure that has actually happened, with what it turned out to be.
It installed correctly. Agent Outlook does not appear on the ribbon by default.
Open a message in read mode — the add-in activates on
ItemIs Message / Read, so drafts and calendar items show nothing — then look
under More apps, or the Apps button on the message's own action bar.
Right-click it there → Pin to put it on the ribbon permanently.
If it is not in that list either, hard-refresh (Ctrl+Shift+R). A fresh sideload usually needs one.
Open the browser console. If you see:
Framing '…' violates the following Content Security Policy directive: "frame-ancestors …"
the add-in's frame-ancestors list does not include the Outlook origin your
tenant is actually served from. Microsoft is migrating Microsoft 365 onto
cloud.microsoft, and many tenants are already there while the commonly-copied
example lists only *.office.com / *.office365.com.
Fix it by appending the newer origins (*.cloud.microsoft,
*.microsoft365.com) to the existing list — do not swap them in, because
tenants on the old origins have not moved.
Also check that no X-Frame-Options header is present. A reverse proxy
adding X-Frame-Options: SAMEORIGIN breaks Outlook on the web while leaving
desktop working, because desktop hosts the pane in a WebView rather than an
iframe. An add-in that "works on desktop but not the web" is this, almost every
time.
That is Next's own error boundary, which means JavaScript threw before the app rendered — not an Outlook problem.
The fastest way to see it is to open the add-in's URL in a plain browser tab.
That is a genuinely useful smoke test even though the pane can never work there:
office.js never completes its host handshake outside an Office client.
The correct outcome in a plain tab is the branded shell showing "Add-in loaded in non-Outlook context", with zero console errors.
So: branded error = healthy. Next's error boundary = a real bug that will also break inside Outlook.
Two page errors, both real, both caused by office.js rather than by Outlook:
| Console error | Cause |
|---|---|
Cannot read properties of null (reading 'bind'), or window.history.replaceState is not a function | office.js nulls history.pushState/replaceState to stop an add-in navigating its host. Next's App Router binds them. Needs a guard installed before office.js loads. |
Cannot read properties of undefined (reading 'CategoryColor') | Office.MailboxEnums was read at module scope, before the host handshake completed. It does not exist yet at that point. |
Both reproduce identically with office.js network-blocked, which is what proves
the library is the culprit rather than the Outlook host.
The pane signed in fine, and then the project list — or any other upstream call — comes back 502 Bad Gateway.
502 here is the add-in reporting that an upstream rejected it, not that the add-in itself crashed. The interesting status is the one behind it, which is usually 403.
A 403 after a successful sign-in almost always means the token is fine but its
issuer string does not match what the upstream expects. This bites in
development: with KC_HOSTNAME_STRICT=false, Keycloak stamps iss from whichever
hostname the request physically arrived on. A token minted through a tunnel URL
carries a different iss than one minted internally — same Keycloak, same signing
keys, different string — and strict issuer validation rejects it.
Fix it upstream by accepting the full set of issuer strings the same realm can
legitimately produce, rather than one. Check the token's iss claim and compare
it to what the upstream validates against before assuming a permissions problem.
In project mode you must pick at least one destination: an inbox, one or more stakeholders, or both. With neither, there is nowhere for the email to go, so the button stays disabled rather than reporting a success that did not happen.
Outside project mode the inbox is the only destination and is always required.
Two independent flags have to line up:
OUTLOOK_PROJECT_MODE must be "true" on the deployment — the exact
string; 1 and yes read as off.stakeholders module enabled in its settings on
agentics.dk.A project-mode instance showing a project with no "Regarding" picker is the second flag being off, and is fixed in the project's settings, not here.
USER_DATA_DIR is not on a persistent volume. The handle in each mailbox's
roamingSettings survives the restart, but the server no longer knows what it
maps to. Mount /data.
Check what the confirmation actually said. The pane reports which destinations succeeded — Agent Share, the stakeholder timeline, or both — and it is honest about a partial result: if the share succeeded and the interaction failed, it says so with a warning rather than claiming both.
If it reported a partial success, the email is in Agent Share and is not on
the timeline. Re-tracking is safe: interactions are keyed on the message's
Message-ID, so the timeline entry cannot be duplicated. The share will be
posted a second time, though — shares are not deduplicated.
A manually sideloaded add-in can take up to 24 hours to appear in classic Outlook, because of caching. New Outlook, Outlook on the web and Outlook for Mac pick it up immediately. This is Outlook's behaviour, not something to debug.