Artifact live mermaid renderer (pinned to 11.16.1) lays out complex flowcharts incorrectly — edges bundle at subgraph borders, implying wrong dependencies

Status Open
Maintainer reply None cached
Activity 0 comments · opened Sep 8, 2026

Summary

An Artifact's live mermaid renderer (/_runtime/mermaid-11.16.1.min.js, injected automatically for any HTML artifact containing <pre class="mermaid">) lays out a complex multi-subgraph flowchart incorrectly — several edges get bundled together where they cross a subgraph border, visually implying dependencies that don't exist in the source. The identical mermaid source renders correctly under a newer mermaid version (11.17.2, via @mermaid-js/mermaid-cli).

This isn't a caching or "stale artifact" issue — I confirmed that directly:

  • Fetched the published artifact's raw HTML server-side (action: "read") — source was correct/unchanged.
  • Republished to a brand-new artifact ID — same bad layout, ruling out any per-artifact cache/version pinning.
  • Rendered the exact same .mmd source through mermaid 11.16.1 (downloaded straight from unpkg.com/mermaid@11.16.1/dist/mermaid.min.js, loaded in a local headless Chromium page with the same mermaid.initialize() config the artifact runtime uses) and got the same bad layout.
  • Rendered the same source through mermaid 11.17.2 (npx @mermaid-js/mermaid-cli) and got a correct layout.

So this is specifically a mermaid-version layout regression between 11.16.1 and 11.17.2 on this class of diagram (many subgraphs, several edges that connect a node in one subgraph to a node several subgraphs away).

Repro

Paste the mermaid source below into any Artifact HTML inside <pre class="mermaid">...</pre>, publish, and view it.

Expected: every edge visually traceable to exactly the two nodes it connects (e.g. full_Deals → airbyte_full_Deals only, full_Users → integration_users only).

Actual (on the live Artifact, mermaid 11.16.1): edges leaving the received_keyed/ subgraph bundle together at the border before diverging, making it look like every node in that subgraph feeds every node in the intermediates//DIRECT subgraphs (e.g. full_Users visually appears to feed airbyte_full_Deals, which has no edge to it in the source).

<details>
<summary>Full repro source (~150 lines)</summary>

flowchart LR
  classDef raw fill:#9aa0a6,stroke:#6f757c,color:#16202b;
  classDef merge fill:#f28e2b,stroke:#bd6d15,color:#241200;
  classDef view fill:#4e79a7,stroke:#31597f,color:#fff;
  classDef tbl fill:#e15759,stroke:#b23a3c,color:#fff;
  classDef fork fill:#edc948,stroke:#b89a1f,color:#241200;

  subgraph REC["received/ — unchanged"]
    direction TB
    R_ACC["Accounts"]
    R_CON["Contacts"]
    R_LEA["Leads"]
    R_DEA["Deals"]
    R_USR["Users"]
    R_CAL["Calls"]
    R_EVE["Events"]
    R_FM["Field_Metadata"]
    R_NOT["Notes"]
    R_TAS["Tasks"]
  end

  subgraph RDP["raw_data_product/ — 10 views, one per stream, plain SELECT * over received/, admits duplicates"]
    direction TB
    V_ACC["Accounts"]
    V_CON["Contacts"]
    V_LEA["Leads"]
    V_DEA["Deals"]
    V_USR["Users"]
    V_CAL["Calls"]
    V_EVE["Events"]
    V_FM["Field_Metadata"]
    V_NOT["Notes"]
    V_TAS["Tasks"]
  end

  subgraph KEY["received_keyed/ — merge, _written_at, enableCursor, no bucketBy, no enableChangeHistory"]
    direction TB
    K_ACC["full_Accounts — + name, domain_name"]
    K_CON["full_Contacts — + name, account_id"]
    K_LEA["full_Leads — + name, domain_name"]
    K_DEA["full_Deals — + name, account_id"]
    K_USR["full_Users"]
    K_CAL["full_Calls"]
    K_EVE["full_Events"]
    K_FM["full_Field_Metadata"]
    K_NOT["full_Notes"]
    K_TAS["full_Tasks"]
  end

  subgraph DIRECT["integration_data_product/ — reads received_keyed/ directly, no intermediate"]
    direction TB
    O_IC["integration_contacts"]
    O_PROPS["properties"]
    O_IU["integration_users"]
  end

  subgraph INT["integration_data_product/intermediates/"]
    direction TB
    I_FDEA["airbyte_full_Deals"]
    I_ENG["airbyte_full_engagements"]
    I_FOBJ["full_objects"]
    I_OM["objects_mapped"]
    I_OP["object_properties"]
    I_LINE["airbyte_full_opportunity_line_items"]
  end

  subgraph IDP["integration_data_product/ — outputs"]
    direction TB
    F_AA["activities_augmented"]
    F_LEC["lifecycle_events_configured"]
    F_LECD["lifecycle_events_custom_dimensions_mapped"]
    F_VMCD["volume_metrics_with_custom_dimensions"]
    F_VMA["volume_metrics_augmented"]
    O_IA["integration_activities"]
    O_IOBJ["integration_objects"]
    O_IOP["integration_object_properties"]
    O_CAV["customer_accounts_with_virtuals"]
    O_ICA["integration_customer_accounts"]
    O_ICAOC["integration_customer_account_ownership_changes"]
    O_ILE["integration_lifecycle_events"]
    O_ILELI["integration_lifecycle_event_line_items"]
    O_ICDVS["integration_custom_dimension_values_sourced"]
  end

  R_ACC --> K_ACC
  R_CON --> K_CON
  R_LEA --> K_LEA
  R_DEA --> K_DEA
  R_USR --> K_USR
  R_CAL --> K_CAL
  R_EVE --> K_EVE
  R_FM --> K_FM
  R_NOT --> K_NOT
  R_TAS --> K_TAS

  R_ACC --> V_ACC
  R_CON --> V_CON
  R_LEA --> V_LEA
  R_DEA --> V_DEA
  R_USR --> V_USR
  R_CAL --> V_CAL
  R_EVE --> V_EVE
  R_FM --> V_FM
  R_NOT --> V_NOT
  R_TAS --> V_TAS

  K_FM --> O_PROPS
  K_CON --> O_IC
  K_LEA --> O_IC
  K_USR --> O_IU

  K_DEA --> I_FDEA
  K_ACC --> I_FOBJ
  K_CON --> I_FOBJ
  K_LEA --> I_FOBJ
  I_FDEA --> I_FOBJ
  K_CAL --> I_ENG
  K_EVE --> I_ENG

  I_FOBJ --> I_OM
  I_FOBJ --> I_OP
  I_FOBJ --> O_IOBJ
  I_OP --> O_IOP
  I_OM --> O_CAV
  O_CAV --> O_ICA
  I_ENG --> F_AA
  F_AA --> O_IA
  I_FOBJ --> F_LEC
  F_LEC --> F_LECD
  F_LEC --> F_VMCD
  F_LECD --> F_VMCD
  F_VMCD --> F_VMA
  F_VMA --> O_ILE
  F_VMA --> O_ICAOC
  O_ILE --> O_ILELI
  I_LINE --> O_ILELI
  I_OM --> O_ICDVS
  F_LECD --> O_ICDVS

  class R_ACC,R_CON,R_LEA,R_DEA,R_USR,R_CAL,R_EVE,R_FM,R_NOT,R_TAS raw;
  class K_ACC,K_CON,K_LEA,K_DEA,K_USR,K_CAL,K_EVE,K_FM,K_NOT,K_TAS,I_FDEA,I_ENG,I_FOBJ,I_OM,I_OP merge;
  class V_ACC,V_CON,V_LEA,V_DEA,V_USR,V_CAL,V_EVE,V_FM,V_NOT,V_TAS,O_PROPS,O_IC,O_IU,O_IA,O_IOBJ,O_IOP,O_ICA,O_ICAOC,O_ILE,O_ILELI,O_ICDVS view;
  class I_LINE,O_CAV tbl;
  class F_AA,F_LEC,F_LECD,F_VMCD,F_VMA fork;

  linkStyle default stroke:#8a94a3,stroke-width:1.3px;

</details>

Environment

  • Product: Claude Code Artifacts (claude.ai/code/artifact/...)
  • Live runtime observed in the published artifact's injected script tag: <script src="/_runtime/mermaid-11.16.1.min.js">
  • Confirmed-good version: mermaid 11.17.2 (current @mermaid-js/mermaid-cli default at time of testing)

Impact

Any moderately complex flowchart Artifact (multiple subgraphs, a handful of edges that skip past an adjacent subgraph) can render with misleading edge topology — worse than illegible, actively wrong — with no visible error and no way to tell from the source alone. Republishing, hard-refreshing, or creating a brand-new artifact ID does not help, since the bug is in the pinned renderer version, not the artifact content or any cache.

Workaround

Render the diagram locally with a mermaid version that lays it out correctly (e.g. @mermaid-js/mermaid-cli, currently resolves to 11.17.2), export to SVG, and embed that static SVG directly in the artifact instead of a live <pre class="mermaid"> block. This sidesteps the artifact's pinned live renderer entirely.

Suggested fix

Bump the artifact runtime's bundled mermaid version past whatever introduced this dagre layout regression (somewhere between 11.16.1 and 11.17.2), or make the version configurable/current.

View original on GitHub ↗