[BUG] addChart() writes an orphan <c:axId> for BAR/LINE charts — third axis ID has no matching <c:serAx>, triggers "repair" dialog in PowerPoint

Open Beginner friendly
#1,534 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
78/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Domain
tooling

Research direction

Run the provided Node.js reproduction and inspect ppt/charts/chart1.xml for the extra axId. Compare the axId emission near line 3846 in dist/pptxgen.cjs.js with the BAR3D-only serAx handling near line 3481, also checking the corresponding .es.js and .bundle.js files. Done means 2D BAR and LINE charts contain two axId elements and open in PowerPoint without repair, while BAR3D retains its series axis reference.

Written by the indexing model from the issue text.

Description

Submission Guidelines
  • I am using the latest release (4.0.1) and the issue is still present
  • I checked the online Documentation — this isn't addressed there
Issue Category
  • Enhancement
  • Bug
  • Question
  • Documentation gap/issue
Product Versions
  • Please specify what version of the library you are using......: [4.0.1]
  • Please specify what version(s) of PowerPoint you are targeting: [Microsoft 365 desktop + PowerPoint Online — both trigger repair]
  • Please specify what web browser you are using.................: [N/A — generated server-side with Node.js]
Desired Behavior

For a 2D BAR chart (and LINE, which shares the same code path), <c:barChart> / <c:lineChart> should declare exactly 2 <c:axId> elements (category + value), matching the two axis definitions actually written to the chart XML. The file should open in PowerPoint without triggering the "repair" dialog.

Observed Behavior

For every BAR (and LINE) chart, PptxGenJS writes three <c:axId> elements:

<c:axId val="2094734554"/><c:axId val="2094734552"/><c:axId val="2094734556"/>

but only two axis parts are ever generated (<c:catAx> with id 2094734554 and <c:valAx> with id 2094734552). The third id, 2094734556 (the AXIS_ID_SERIES_PRIMARY constant), is never backed by a <c:serAx> element unless the chart type is BAR3D.

This is a dangling axis reference, invalid per the OOXML chart schema. LibreOffice ignores it silently, but PowerPoint rejects the file and shows "We found a problem with some content... repair" on every open. PowerPoint's own repair simply strips the extra axId.

This affects every deck containing at least one 2D bar or line chart — not just combo/secondary-axis charts.

Root cause — in dist/pptxgen.cjs.js (same in .es.js / .bundle.js):

// lines 64–68
const AXIS_ID_VALUE_PRIMARY = '2094734552';
const AXIS_ID_CATEGORY_PRIMARY = '2094734554';
const AXIS_ID_SERIES_PRIMARY = '2094734556';

BAR, BAR3D, and LINE share the same switch-case branch when building the plot area. The axId list is written unconditionally there (~line 3846):

strXml += `<c:axId val="${catAxisId}"/><c:axId val="${valAxisId}"/><c:axId val="${AXIS_ID_SERIES_PRIMARY}"/>`;

But the corresponding <c:serAx> element — the only thing that would make the third axId valid — is correctly gated to BAR3D only, elsewhere in the same file (~line 3481):

if (rel.opts._type === CHART_TYPE.BAR3D) {
    strXml += makeSerAxis(rel.opts, AXIS_ID_SERIES_PRIMARY, AXIS_ID_VALUE_PRIMARY);
}

The axId-emission line doesn't check _type the way makeSerAxis's caller does, so the reference and the definition fall out of sync for any non-3D bar chart (and for line charts, going through the same branch).

Suggested fix:

strXml += `<c:axId val="${catAxisId}"/><c:axId val="${valAxisId}"/>`;
if (chartType === CHART_TYPE.BAR3D) {
    strXml += `<c:axId val="${AXIS_ID_SERIES_PRIMARY}"/>`;
}
Steps to Reproduce
const pptxgen = require("pptxgenjs");
let pres = new pptxgen();
let slide = pres.addSlide();
slide.addChart(pres.ChartType.bar, [
  {
    name: "Series 1",
    labels: ["2023", "2024", "2025"],
    values: [10, 20, 30],
  },
], { x: 1, y: 1, w: 6, h: 4 });
pres.writeFile({ fileName: "repro.pptx" });
  1. Run the snippet above.
  2. Open repro.pptx in PowerPoint (desktop or online) → "repair" dialog appears.
  3. Open the same file in LibreOffice Impress → opens without warning.
  4. Unzip the pptx and inspect ppt/charts/chart1.xml: 3 <c:axId> under <c:barChart>, but only 1 <c:catAx> and 1 <c:valAx> in the whole file — no <c:serAx>.

Workaround for anyone hitting this before a fix ships: post-process the generated .pptx (it's a zip) after writeFile()/write(), stripping <c:axId val="2094734556"/> from any ppt/charts/chart*.xml that has no matching <c:serAx> in the same file. Happy to share the small Node/JSZip snippet if useful.

Dominant language
TypeScript
Stars
6.2k
Forks
953
PR merge metrics
No merged PRs in 30d

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from gitbrent/PptxGenJS

All issues in gitbrent/PptxGenJS

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.