Errors on the platform come from four places: the response model allow-list, the Smarty security policy, a method called on nothing, and the platform's routing. Each has a signature. On a development environment every error page carries the stack trace and the template and line; on production the site's error page shows and the error is recorded under Template Errors in the admin.
Errors and blank pages
Thirteen error messages and empty responses, what each one means on this platform, and how to resolve it, with the Smarty and Twig behaviour where the two engines differ.
"Method X does not exist" when rendering a record
A template may only call the methods listed for that record's response model; the entity may well have the method, and the template still cannot. Look the record up on the Entities reference and use a listed method, or reach the value another way (through a relation that does expose it, or a layout area). Twig does not raise this: it renders nothing, so the same mistake on a Twig site is an empty space with no message.
"Property X does not exist" from a shorthand area call
$component->heading resolved neither a getter nor a layout area of that name on the record's layout. A typo, a layout area on a different layout, a layout area added but not saved, or an older revision on a layout without it. Guard optional areas with hasAreaWithName(), or use getAreaText(), which returns nothing for a missing area instead of throwing. Twig renders nothing for the same call.
A shorthand call returns a getter's value instead of my area
The layout area is named after a method the record already has (name, id, url, slug, text, type, parent, position, created, published and the rest): the shorthand finds the getter first and never reads the layout area. Rename the area for what it holds (heading, ctaUrl), or read it explicitly with getAreaText('name'), which always means the area.
A completely blank white page
A component's template threw. An error inside a component or a linked record does not stop the rest of the page from rendering, so a page whose whole body is one component can render blank. Look under Template Errors in the admin, or open the page on the development environment where the trace shows. Other blanks: the site's own 500 page failed while rendering (keep fatal-error.html self-contained), or the content sits inside a {literal} that was never closed.
A 500 with no detail on production
By design: the detail depends on the environment, not on who is signed in, so production shows your site's error page to everyone and writes the error to Template Errors in the admin. Read it there, or reproduce on the development environment, which shows the full trace to everyone.
403 on a form submission or a POST from JavaScript
The CSRF token is missing or stale: every POST from a signed-in session must carry _csrfToken, which is only defined when someone is signed in, so a form on a page seen signed out must use {$_csrfToken|default:''}. Then: the call goes to /cdna-api from a site member's session, which cannot use the API at all (a 404 by default, and a 403 only where the security setting Access Denied (Authenticated) shows the Forbidden page); a write to the API without an Authorization header or a backend session; or an API key sent to the wrong hostname. A restricted record answers 404 by default, not 403, so a real 403 is almost always authentication or CSRF.
404 on an API endpoint that exists
The list path is module plus entity: /cdna-api/pages/pages, not /cdna-api/pages; custom entity records are /cdna-api/custom-entities/<plural identifier>. Then: GraphQL is POST /cdna-api/graphql and a GET is a 404; the API is per hostname, so the development hostname's API does not see production; and a wrong entity segment is a 404 while a request with no credential is a 401, which tells the two apart. More causes, with real answers: The API answers 404 for a record that exists.
404 on a page under /my-account/
The catch-all maps /my-account/<path> to templates/my-account/<path>.html in your site's folder, with no index fallback, so /my-account/courses needs courses.html, not courses/index.html. A dot in the path matches nothing; a name that collides with a built-in screen (orders, addresses, quotes, wishlist) renders the built-in screen; and case matters. A signed-out visitor is redirected to /login, not shown a 404, so a 404 means the file.
A Smarty syntax error I cannot locate
On the development environment the error names the template and the line. The usual causes: an unclosed {if} or {foreach}; a { in inline CSS or JavaScript with no space after it, which Smarty reads as a tag (wrap the block in {literal}); a {* comment *} inside an array literal; a nested comment; and a security-policy refusal, whose message names the modifier or function, and which looks like a syntax error until you read it.
"Call to a member function on null" in a template
A chain went through an empty relation: getParent() on the root page, getAreaRecord() on an empty area, getShareImage() with none set, getActiveRevision() on a record that has none, _menu->get() for a renamed menu. Assign the intermediate value and test it before calling anything on it. The frontend returns blank objects for images, components, widgets and raw content, so those chains are safe; files, records and relations return nothing, and are not.
{$parent = $page->getParent()}
{if $parent}<a href="{$parent->getFullPath()}">Up</a>{/if}
{% set parent = page.getParent() %}
{% if parent %}<a href="{{ parent.getFullPath() }}">Up</a>{% endif %}
A Smarty template seems to skip a PHP function I called
It does not: a function outside the policy fails the compile with a message, so silence means the call is not being compiled. It sits inside {literal} or a comment; the file you edited is not the one rendering (a same-named site or platform file wins, or the layout points elsewhere); production is still serving the compiled template from before the deploy; or the site is Twig, which ignores an unknown method and renders nothing.
A Twig template errors on an undefined variable that used to render empty
Strict variables are off for every template file: an undefined variable renders as nothing. The one strict context is email subjects and bodies rendered from templates, which raise on a missing variable and fall back to plain placeholder substitution. Guard with |default('') or is defined, and remember that on a response model is defined is true for every name, so it guards nothing there; test the value instead.
Output is double-escaped, or not escaped at all, after a template was ported
Neither engine escapes output on this platform, and |raw changes nothing. Two ports go wrong in opposite ways: a developer arriving from stock Twig adds |e everywhere and rich text prints as visible tags, or & appears where a value was escaped twice; a template ported from stock Twig relied on autoescaping and now prints visitor input raw. Carry every |escape across as |e, add none for rich text, and add one wherever plain text from a visitor, a URL or a feed is printed.
Was this page helpful?
Your answer goes to the docs team.