PptxGenJS gotchas that silently break your PowerPoint: the complete guide
PptxGenJS has 1.27 million weekly downloads and a list of silent bugs that corrupt PowerPoint output without error messages. Reusing option objects mutates them. Combo charts trigger repair dialogs. Uppercase image paths break files. This guide documents every known gotcha with code fixes.
PptxGenJS has 1.27 million weekly downloads and is the most popular JavaScript library for PowerPoint generation. It is also full of silent failure modes — bugs that produce corrupted output without throwing errors. Option objects get mutated in-place. Combo charts trigger repair dialogs. Uppercase image paths break files. This guide documents every known gotcha with the broken code and the fix, sourced from GitHub issues, production debugging, and Anthropic's OOXML skills documentation.
Gotcha 1: option object mutation
According to Anthropic's PptxGenJS reference: "NEVER reuse option objects across calls — PptxGenJS mutates objects in-place (e.g. converting shadow values to EMU). Sharing one object between multiple calls corrupts the second shape."
const shadow = {
type: "outer", blur: 6, offset: 2,
color: "000000", opacity: 0.15
};
slide.addShape(pres.shapes.RECTANGLE, { shadow, x: 1, y: 1 });
// ❌ shadow object is now mutated (values converted to EMU)
slide.addShape(pres.shapes.RECTANGLE, { shadow, x: 3, y: 1 });
Fix — factory function
const makeShadow = () => ({
type: "outer", blur: 6, offset: 2,
color: "000000", opacity: 0.15
});
slide.addShape(pres.shapes.RECTANGLE, { shadow: makeShadow() });
// ✅ fresh object — no mutation problem
slide.addShape(pres.shapes.RECTANGLE, { shadow: makeShadow() });
This is the most common silent failure in PptxGenJS. The first shape renders correctly; the second shape has wrong dimensions, wrong shadow size, or missing formatting. There is no error, no warning, no repair dialog — just visually wrong output that passes through code review because the code looks correct.
Gotcha 2: combo charts trigger repair dialog
According to PptxGenJS release notes, issue #1013 documented that "chart with lines and bars produces repair file dialog in PowerPoint." The fix was released in v4.0.1 (June 2025), but combo charts with secondaryValAxis and secondaryCatAxis can still produce repair dialogs when the options are inconsistent.
const chartTypes = [
{ type: pres.charts.BAR, data: barData },
{ type: pres.charts.BAR, data: avgData,
options: {
secondaryValAxis: true,
secondaryCatAxis: true, // ❌ causes repair on Windows Office
}
}
];
slide.addChart(chartTypes, opts);
Fix — hide secondary category axis
const opts = {
valAxes: [
{ showValAxisTitle: true, valGridLine: "solid" },
{ valAxisHidden: true, valGridLine: "none" } // ✅ hide secondary
],
};
slide.addChart(chartTypes, opts);
This issue was platform-specific — files opened correctly in LibreOffice on macOS but triggered repair on Windows Office. Always test PptxGenJS output on Windows PowerPoint, not just macOS or web viewers. For the full OOXML explanation of why this happens, see why PPTX triggers repair dialogs.
Gotcha 3: uppercase image paths
According to PptxGenJS v4.0.1 release notes, issue #860 documented that "using addImage() with uppercase path prop causes needs to repair presentation." OOXML relationship targets are case-sensitive inside the ZIP archive.
slide.addImage({ path: "./images/logo.PNG" }); // ❌ .PNG (uppercase)
Fix — lowercase paths
slide.addImage({ path: "./images/logo.png" }); // ✅ .png (lowercase)
// Or normalize programmatically:
const safePath = imagePath.toLowerCase();
slide.addImage({ path: safePath });
Gotcha 4: "Edit Data in Excel" broken on charts
According to the PptxGenJS v4.0.1 release notes, "several issues with charts embedded Excel sheets that prevented Edit Data in Excel from working" were fixed. If you are on an older version, chart data cannot be edited by the recipient — clicking "Edit Data" in PowerPoint either does nothing or shows an error.
Fix — upgrade to v4.0.1+
npm install pptxgenjs@latest
If upgrading is not possible, the chart data is still correct — only the "Edit Data in Excel" feature is broken. The chart displays correctly; it just cannot be modified by the recipient.
Gotcha 5: ROUNDED_RECTANGLE with accent borders
According to Anthropic's reference: "Don't use ROUNDED_RECTANGLE with accent borders — rectangular overlay bars won't cover rounded corners."
Fix — use RECTANGLE instead
// ❌ ROUNDED_RECTANGLE + colored border = visual artifact
slide.addShape(pres.shapes.ROUNDED_RECTANGLE, {
rectRadius: 0.1,
line: { color: "4580B0", width: 2 }
});
// ✅ Use RECTANGLE — clean border rendering
slide.addShape(pres.shapes.RECTANGLE, {
line: { color: "4580B0", width: 2 }
});
Gotcha 6: single-series bar chart with chartColors
According to issue #285, providing a chartColors array to a bar chart with a single data series causes the chart to render incorrectly. The legend shows all category labels as separate entries, and the bars display wrong colors.
Fix — single-element color array
// ❌ Array of colors with single series = broken rendering
slide.addChart(pres.charts.BAR, data, {
chartColors: ["4580B0", "C4453A", "B58215"]
});
// ✅ Single-element array for single series
slide.addChart(pres.charts.BAR, data, {
chartColors: ["4580B0"]
});
Gotcha 7: table auto-paging with complex text
According to the PptxGenJS release notes, table auto-paging was "completely re-written from scratch" in v3.12 to handle complex text (text runs with mixed formatting). If you are on an older version, tables with styled text runs (bold + italic + links in the same cell) may overflow the slide without creating a new page.
Fix — upgrade to v3.12+ and use autoPageRepeatHeader
slide.addTable(rows, {
autoPage: true,
autoPageRepeatHeader: true,
autoPageLineWeight: 0.5, // reduce for tighter fits
autoPageCharWeight: 0.5, // reduce for more chars/line
});
The autoPageLineWeight and autoPageCharWeight options control how aggressively the auto-pager breaks content. Lower values fit more content per slide at the cost of tighter spacing. Test with your actual data — the defaults may over-paginate.
The alternative: skip OOXML entirely
Every gotcha above stems from the same root cause: PptxGenJS generates raw OOXML, and OOXML has strict element ordering, relationship ID, and content type requirements that are easy to violate. The JSON layer pattern avoids these issues entirely — you define the document as JSON, and a rendering engine handles OOXML compliance.
PaperJSX's free PPTX engine (MIT-licensed) generates valid OOXML from JSON schemas. No option object mutation, no relationship ID management, no element ordering concerns. The same JSON produces PPTX, PDF, DOCX, and XLSX. For the free PPTX quickstart, see Generate PPTX from JSON. For a migration path from PptxGenJS, see the three-way comparison.

