Troubleshooting · Developer docs

Troubleshooting

Grouped by symptom, never by module, because the person with the problem does not know which module has it. One hundred questions across ten pages, each answered with the causes in the order they usually turn out to be true.

Symptom 13 questions

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.

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.

"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.

Open this answer on its own page →
"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.

Open this answer on its own page →
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.

Open this answer on its own page →
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.

Open this answer on its own page →
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.

Open this answer on its own page →
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.

Open this answer on its own page →
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.

Open this answer on its own page →
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.

Open this answer on its own page →
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.

Open this answer on its own page →
"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.

Template code
{$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 %}
Open this answer on its own page →
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.

Open this answer on its own page →
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.

Open this answer on its own page →
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 &amp; 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.

Open this answer on its own page →
Go deeper

Was this page helpful?

Your answer goes to the docs team.