Advanced PDF/HTML Templates in NetSuite are powerful, but their mix of XML, inline CSS, FreeMarker, and BFO (Big Faceless Organization) rendering means they can fail in surprisingly subtle ways. In this deep-dive companion to our Using FreeMarker for Dynamic Content post, we walk through the most common errors NetSuite developers and administrators encounter when working with Advanced PDF Templates β and exactly how to debug and fix each one.
1. “Expression record.xxx is undefined” (FreeMarker Null Reference)
This is the single most common error when working with Advanced PDF Templates. It happens because FreeMarker treats missing or null fields as undefined rather than as empty strings.
Typical error message:
Expression record.custbody_delivery_notes is undefined on line 42, column 18.
How to debug:
- Check the field’s internal ID matches exactly (custbody fields are case sensitive).
- Verify the field is actually populated on the transaction you are previewing.
- Use FreeMarker’s missing-value operator (
!) to provide a fallback.
Fix:
2. “Cannot get property X of null”
This happens when you traverse a relationship that doesn’t exist β for example, accessing record.entity.companyname when the customer has no parent company, or referencing a subsidiary field on a single-instance account.
How to debug:
- Wrap the traversal in a
<#if record.entity?? && record.entity.companyname??>block. - Use the safe navigation pattern:
${(record.entity.companyname)!"N/A"}. - Confirm the linked record type exists by checking
?keyson the parent object.
3. “Parse error: Encountered <” or “Unexpected end of file”
FreeMarker is strict about tag closure and XHTML compliance. A single unclosed <div> or unescaped & in static text will break the entire render.
How to debug:
- Look at the line and column number β FreeMarker is usually accurate.
- Validate the template XML in an XML validator outside of NetSuite.
- Replace
&with&in any hard-coded labels. - Make sure every
<#if>,<#list>, and<#macro>has a matching closing tag.
4. “Method public X.Y is not allowed in the template”
NetSuite sandboxes FreeMarker to block direct method calls on Java/SuiteScript objects. You’ll see this when trying to call methods like .getValue() or .toString() directly.
Fix: Pre-process the data in a Suitelet, RESTlet, or workflow custom field and reference the resulting field instead of invoking a method inside the template.
5. PDF Renders Blank or Missing Sections
The template generates without errors but the resulting PDF is blank, has missing tables, or shows overlapping text. This is almost always a BFO rendering issue.
How to debug:
- BFO requires valid XHTML. Self-close
<br/>,<img/>, and<hr/>. - Avoid
display:flex,display:grid, and modern CSS β use tables for layout. - Set explicit widths on table columns; auto-sizing often collapses to zero.
- Move all CSS inline. External or
<style>-block selectors can silently fail.
6. “Image cannot be loaded” or Broken Logos
Logos disappear in production even though they show in preview. This is usually a permissions or URL issue.
- Confirm the file in the File Cabinet is marked Available Without Login.
- Use the file’s absolute URL, not a relative path.
- Avoid query strings on image URLs β BFO can mis-parse them.
- Test the URL in an incognito browser window to verify public access.
7. Loops That Print Nothing
A <#list record.item as item> block renders no rows even though the transaction clearly has line items.
Common causes and fixes:
- You are using the wrong sublist key. Try
record.item.itemfor transactions and inspect with${record?keys}. - The line items are filtered by
itemtypeβ check for “EndGroup” and “Subtotal” rows. - The template’s record type doesn’t match the transaction (e.g., a Sales Order template used on an Invoice).
8. “Cannot compare X to Y” Type Errors
FreeMarker is strongly typed. Comparing a string to a number, or a date to a string, throws an error.
<#-- Wrong --> <#if record.total > "100"> ... <#-- Right --> <#if record.total?number > 100> ...
9. Encoding and Special Character Errors
Customer names with &, <, >, or non-ASCII characters can break rendering. Always run untrusted text through the ?html or ?xml built-in:
${record.entity.companyname?html}
10. A Repeatable Debugging Workflow
When you hit an error, follow this checklist before changing the template:
- Read the line and column reported in the error β FreeMarker is precise.
- Comment out half the template and re-test (binary search) to isolate the failing block.
- Dump the data with
<pre>${record?keys?join(", ")}</pre>to see what’s actually available. - Compare against a known-working template for the same record type.
- Test in a sandbox with a representative transaction before deploying to production.
- Version control your template β copy/paste into a Git repo or SDF project before each change.
Final Thoughts
Most Advanced PDF Template errors come down to three root causes: missing data, invalid XHTML, or unsupported CSS. With safe-navigation operators, strict XHTML, and inline styles, you can eliminate the majority of issues before they reach production. Bookmark this guide as your first stop when a template starts misbehaving β and in the next post, we’ll cover integrating saved searches into Advanced PDF Templates for richer, report-style documents.
Discover more from The NetSuite Pro
Subscribe to get the latest posts sent to your email.
Leave a Reply