Skip to content

fix(mermaid): pass original error to errorComponent via cause prop - #722

Open
aradhyacp wants to merge 6 commits into
vercel:mainfrom
aradhyacp:fix/mermaid-error-cause
Open

aradhyacp wants to merge 6 commits into
vercel:mainfrom
aradhyacp:fix/mermaid-error-cause

Conversation

@aradhyacp

Copy link
Copy Markdown
Contributor

Description

The Mermaid errorComponent only received the error message string, so the original thrown error (for example a Jison parse error with its hash) was discarded in renderChart. Consumers who wanted structured parser details had to call mermaid.parse(chart) a second time. That is wasted work, and the second parse may not reproduce the original failure, for example when parsing succeeds but rendering fails.

This PR adds an optional cause?: unknown prop to MermaidErrorComponentProps and forwards the original thrown value to the custom error component.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Performance improvement
  • Refactoring (no functional changes)

Related Issues

Fixes #720

Changes Made

  • Added optional cause?: unknown to MermaidErrorComponentProps (packages/streamdown/index.tsx)
  • renderChart now returns the original thrown value as cause in the failure outcome, including non-Error values (packages/streamdown/lib/mermaid/index.tsx)
  • Store the cause in an errorCause state and pass it to ErrorComponent
  • Clear errorCause when a new render starts and when the plugin is missing, so a stale cause never pairs with a newer error
  • Added unit tests for forwarding an Error with a Jison-style hash and a non-Error thrown value
  • Documented cause in the Mermaid docs page and the skill API reference
  • Added a changeset (patch)

Testing

  • All existing tests pass
  • Added new tests for the changes
  • Manually tested the changes

How I tested it locally:

I linked the local build into a test React app and used the component below with two invalid diagrams, one Jison-based (flowchart) and one Langium-based (architecture-beta).

Test component
import { Streamdown } from "streamdown";
import { mermaid } from "@streamdown/mermaid";
import type { MermaidErrorComponentProps } from "streamdown";
import "streamdown/styles.css";

const CustomMermaidError = ({
  error,
  chart,
  cause,
  retry,
}: MermaidErrorComponentProps) => {
  console.log("Error message:", error);
  console.log("Original chart:", chart);
  console.log("New Cause Prop:", cause);

  return (
    <div>
      <h3>Mermaid Error</h3>

      <p>The error message is: {error}</p>

      <pre>The original chart is: {chart}</pre>

      <button onClick={retry}>Retry</button>
      <pre>The cause is: {JSON.stringify(cause)}</pre>
      <pre>The error function is: {JSON.stringify(error)}</pre>
    </div>
  );
};

const App = () => {
  const markdown = `
# Hello World

\`\`\`mermaid
graph TD
    A[Start] --> B{Decision}
    B -->|Yes| C[Success]
    B -->|No| D[Try Again
    D --> B
\`\`\`

# Langium Parser Test

\`\`\`mermaid
architecture-beta
    service api(server)[API Server]
    service db(database)[Database]

    api:R --> db:L
    invalid syntax here
\`\`\`
`;

  return (
    <div className="App">
      <Streamdown
        plugins={{ mermaid }}
        mermaid={{ errorComponent: CustomMermaidError }}
      >
        {markdown}
      </Streamdown>
    </div>
  );
};

export default App;

Results

  • Jison (flowchart): cause is the original error, and cause.hash exposes token, line, loc and expected (15 expected tokens). No second mermaid.parse is needed.
  • Langium (architecture-beta): cause is forwarded, but it has no hash (cause.hash === undefined). The error shape differs per parser, which is why the prop is typed unknown. The docs tell consumers to check the shape before reading properties.
  • The existing error, chart and retry props are unchanged.

Test Coverage

Two new unit tests in packages/streamdown/__tests__/mermaid-component.test.tsx:

  • an Error carrying a Jison-style hash reaches the errorComponent as the same object
  • a non-Error thrown value is forwarded as cause

Screenshots/Demos

Before (cause not available)

image

After, Jison error (cause.hash available)

image

After, Langium error (cause forwarded, no hash)

image

Checklist

  • My code follows the project's code style
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings or errors
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • I have created a changeset (pnpm changeset)
  • All my commits are signed

Changeset

  • I have created a changeset for these changes

Additional Notes

  • cause is optional, so existing custom error components keep working.
  • cause is typed unknown because it is whatever Mermaid threw. Jison errors expose hash, Langium errors do not, and a non-Error value can be thrown.
  • Because this forwards the exact thrown value, consumers can send structured parser details to error-tracking services without re-parsing the chart.

@vercel

vercel Bot commented Nov 8, 2026

Copy link
Copy Markdown
Contributor

@aradhyacp is attempting to deploy a commit to the Vercel Team on Vercel.

A member of the Team first needs to authorize it.

@aradhyacp aradhyacp changed the title Fix/mermaid error cause fix(mermaid): pass original error to errorComponent via cause prop Nov 8, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Pass the original error to Mermaid errorComponent

1 participant