Errors, limits and versioning

Errors

A command that fails rejects with an EmbedError. Its code is stable and meant to be branched on; message is written for a developer reading a console.

const { EmbedError } = IconMapEmbed;

try {
  await map.applyBookmark({ bookmarkId });
} catch (e) {
  if (!(e instanceof EmbedError)) throw e;
  switch (e.code) {
    case "unknown_id":        return forgetBookmark(bookmarkId);
    case "denied_capability": return hideBookmarkMenu();
    default:                  report(e.code, e.message, e.requestId);
  }
}
Property
code One of the error codes
message What went wrong, in a sentence
detailedMessage The underlying cause, when there is one
requestId Present when the failure involved our servers - quote it in a support request
detail Structured extras, for example { undeclared: [...] } on undeclared_filter

Which code means what

The codes fall into four families, and the right response differs for each.

Your page is not allowed - denied_origin, denied_capability. The author decides these. denied_origin rejects ready itself: no session opened, and nothing will work until your site is added to the map's allowed origins. denied_capability means one group is off (or, for exportImage and print, that a sensitivity label refuses the export). Hide the feature; retrying cannot help.

The map does not have it - unsupported_command, unknown_id, undeclared_filter. Check capabilities.commands before offering a feature, and build pickers from what the map reports (getLayers, getBookmarks, getFilterSchema) rather than from ids in your code.

The call was wrong - invalid_args, too_large. A bug in the calling code; the message names the argument.

Try again later - rate_limited, busy, budget_exceeded, data_error, timeout, not_ready. Back off rather than loop.

Two codes come from the SDK rather than the map: timeout (no answer within 15 seconds; change with the commandTimeoutMs option) and destroyed (you destroyed or reloaded the map while a command was in flight).

Start-up failures

If the map cannot start at all - a revoked publish, a token refused - ready rejects and the onError option is called. The map shows its own message to the reader unless you pass hideErrors: true and show yours.

Limits

These are fixed. Your page cannot raise them and an author cannot lower them; they are also exported as EMBED_LIMITS.

Limit Value When exceeded
Commands 60 a second rate_limited
One command message 64 KB too_large, and the command is never read
One event payload 32 KB the event is dropped
Keys in highlight / selectByKey 500 invalid_args
Analysis operations 60 a minute, 1 running + 4 waiting per layer budget_exceeded, busy
Analysis results 1,000 ids or 200 rows per list cut, with truncated: true
featureHover one per 100 ms coalesced - the last value always arrives

Capabilities, not versions

await map.ready resolves with a descriptor of what this map will answer:

{
  protocol: 2,
  commands: ["getView", "setView", ...],
  events:   ["viewChanged", "featureClick", ...],
  policy:   { enabled: true, read: true, camera: true, layers: true, ... },
  map:      { publishId, surface: "published", dataMode: "snapshot", bookmarks: true, locales: ["en-US", "de-DE", ...] }
}

commands is already the intersection of three things: what this version of the map implements, what this kind of embed supports, and what the author switched on. So the only check you ever need is:

if (capabilities.commands.includes("exportImage")) showExportButton();

New commands arrive by being added to that list. A page written today keeps working; a page that wants a newer command asks for it and degrades when it is absent.

Compatibility between old and new

The map and the SDK are released separately, so each copes with the other being older.

Your page uses The map is What happens
Current SDK Current Everything in this documentation
Current SDK An older map without the control API The map displays. ready resolves with an empty commands list rather than hanging; commands reject unsupported_command
SDK 0.x (display and setFilters only) Current Works unchanged

The version agreed is in map.protocol. You should not need it.

Lifecycle

map.reload();      // reload the frame; subscriptions are restored when it is back
map.destroy();     // remove the frame; anything in flight rejects with `destroyed`

getEmbed(element) returns the handle already mounted in an element, and reset(element) destroys it - useful in frameworks where the code that mounts the map is not the code that cleans up.

Security model

For a security review, the properties that matter:

  • Isolation. The map runs in a cross-origin iframe. It cannot read your page, and your page cannot read it; the only channel is postMessage.
  • Who may speak. The map accepts messages only from the window that framed it, and only if that window's origin is on the author's allowed origins. A third-party frame on your page cannot drive the map, even from an allowed origin. The SDK in turn accepts messages only from the frame it created, on the origin it expects, and sends tokens nowhere else.
  • What may be said. A closed list of commands with validated arguments. None takes a URL, a query, a style, HTML or script.
  • What comes back. Only what a reader can already see: tooltip fields, never whole rows; never the map's configuration, data sources or queries.
  • Who decides. Allowed origins and the command-group switches are part of the signed publish, enforced inside the map - and, where a command reaches our servers (refreshData), enforced there as well.
  • Data access is unchanged. The API adds no new route to data. A published map reads what the publish froze or what its token's row-level security allows; an organizational embed reads as the signed-in viewer.
  • Sensitivity labels. Image export and print are decided by the same sensitivity-label rules as every other export from Icon Map.
  • Telemetry. We count control sessions and which command groups are used. Argument values - filter values, selections, your menu titles - are never collected.

The same allowed-origins list also sets the frame-ancestors policy, so it governs which sites can frame the map at all.