Use when debugging unexpected pdf-lib behavior — blank pages, wrong positions, missing content, or runtime errors. Prevents the top 10 pdf-lib mistakes: forgotten await, wrong coordinate origin, unsupported image formats, cross-document page errors, case-sensitive field names, color values 0-255 instead of 0-1. Covers async errors, coordinate bugs, image format errors, form field issues. Keywords: debug, blank page, wrong position, undefined, await, coordinate, 0-255, field not found, PDF is blank, text in wrong place, nothing shows up, PDF broken, content missing.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
Use when debugging unexpected pdf-lib behavior — blank pages, wrong positions, missing content, or runtime errors. Prevents the top 10 pdf-lib mistakes: forgotten await, wrong coordinate origin, unsupported image formats, cross-document page errors, case-sensitive field names, color values 0-255 instead of 0-1. Covers async errors, coordinate bugs, image format errors, form field issues. Keywords: debug, blank page, wrong position, undefined, await, coordinate, 0-255, field not found, PDF is blank, text in wrong place, nothing shows up, PDF broken, content missing.
license
MIT
compatibility
Designed for Claude Code. Requires pdf-lib 1.x with TypeScript/JavaScript.
metadata
{"author":"OpenAEC-Foundation","version":"1.0"}
Common pdf-lib Errors: Diagnosis & Fixes
Non-font, non-loading errors. For font/encoding errors see pdflib-errors-fonts.
For document loading errors see pdflib-errors-loading.
Quick Diagnostic Checklist
When pdf-lib code produces unexpected results, check these in order:
Missing await? — embedFont, embedPng, , , ALL return Promises
embedJpg
copyPages
save
Y-coordinate wrong? — PDF origin is BOTTOM-LEFT, not top-left
Unsupported image format? — ONLY PNG and JPG are supported
Cross-document page copy? — MUST use copyPages() before addPage()
Form field not found? — Names are case-sensitive and fully qualified (dot-separated)
Color looks wrong? — rgb() takes 0.0–1.0, NOT 0–255
Unexpected blank page? — save() adds one if document has zero pages
Form appearances changed? — save() auto-updates field appearances by default
Decision Tree: "My PDF Output Looks Wrong"
PDF output is wrong
├── Content is missing entirely
│ ├── Used embedFont/embedPng without await? → See §1
│ ├── Copied page without copyPages()? → See §4
│ └── save() returned empty bytes? → Check await on save()
├── Content is in wrong position
│ ├── Text/image appears at bottom instead of top? → See §2
│ └── Ellipse/circle shape is wrong? → See §11
├── Colors are wrong
│ └── Used 0-255 instead of 0-1? → See §6
├── Form fields don't work
│ ├── "No field with name X" error? → See §5
│ ├── Duplicate field name error? → See §7
│ └── Field appears empty until clicked? → See §9
├── Merged PDF has issues
│ ├── Error when adding page from another doc? → See §4
│ └── copy() lost form fields/bookmarks? → See §8
└── Unexpected extra page
└── Empty document got blank page on save? → See §10
§1 Forgotten await on Async Methods
Severity: CRITICAL — Most common cause of "everything breaks silently."
These methods return Promise — you MUST await them:
Method
Returns
embedFont()
Promise<PDFFont>
embedPng()
Promise<PDFImage>
embedJpg()
Promise<PDFImage>
copyPages()
Promise<PDFPage[]>
save()
Promise<Uint8Array>
saveAsBase64()
Promise<string>
copy()
Promise<PDFDocument>
embedPdf()
Promise<PDFEmbeddedPage[]>
Broken:
const font = pdfDoc.embedFont(StandardFonts.Helvetica);
page.drawText('Hello', { font }); // font is a Promise, NOT a PDFFont!
Fixed:
const font = await pdfDoc.embedFont(StandardFonts.Helvetica);
page.drawText('Hello', { font });
ALWAYS use await on every embed*, copy*, save*, and load call.
§2 Coordinate System Confusion (Bottom-Left Origin)
Severity: HIGH — PDF uses bottom-left origin. HTML/CSS/Canvas uses top-left.
Broken:
// Developer expects y=50 to be near the top
page.drawText('Title', { x: 50, y: 50 }); // Appears near BOTTOM
Fixed:
const { height } = page.getSize();
page.drawText('Title', { x: 50, y: height - 50 }); // Near TOP
ALWAYS subtract from page.getSize().height when positioning from the top.
NEVER assume y=0 is at the top of the page.
§3 Unsupported Image Formats
Severity: HIGH — pdf-lib supports ONLY PNG and JPG. No GIF, BMP, SVG, WebP, or TIFF.
Method
Format
embedPng()
PNG only
embedJpg()
JPG/JPEG only
There is NO embedImage(), embedGif(), embedBmp(), or embedSvg() method.
Fix: Convert images to PNG or JPG before embedding using an external library (e.g., Sharp, Canvas API, or browser canvas).
ALWAYS convert non-PNG/JPG images before passing to pdf-lib.
NEVER attempt to pass GIF, SVG, BMP, or WebP bytes to embed methods.
§4 Cross-Document Page Addition Without copyPages()
Severity: CRITICAL — Pages from one document CANNOT be added directly to another.
ALWAYS call copyPages() on the TARGET document first.
ALWAYS addPage() or insertPage() each copied page — copyPages() alone does NOT add them.
§5 Form Field Not Found (Case-Sensitive, Fully Qualified Names)
Severity: HIGH — Field names are case-sensitive and use dot-separated hierarchical names.
Broken:
form.getTextField('name'); // Throws if actual name is "form.personal.Name"
Fixed:
// ALWAYS enumerate fields first to discover exact namesconst fields = form.getFields();
fields.forEach(field => {
console.log(`Type: ${field.constructor.name}, Name: "${field.getName()}"`);
});
// Then use the exact name from enumerationconst nameField = form.getTextField('form.personal.Name');
ALWAYS enumerate fields with getFields() before accessing by name.
NEVER guess field names — they are case-sensitive and may include parent prefixes.
§6 Color Values: 0.0–1.0, NOT 0–255
Severity: MEDIUM — All color functions use normalized 0.0–1.0 range.
ALWAYS pass { updateFieldAppearances: false } to save() when you want to preserve existing field appearances exactly as they are.
§10 save() Adds Blank Page If Document Is Empty
Severity: LOW — Calling save() on a document with zero pages automatically inserts one blank page, because the PDF specification requires at least one page.
ALWAYS add at least one page before calling save() to avoid unexpected blank pages.
§11 Drawing Method Parameter Names
Severity: MEDIUM — Some drawing methods use non-obvious parameter names.