attempt, recover

Synopsis

<#attempt>
  attempt block
<#recover>
  recover block
</#attempt>

Where:

  • attempt block: Template block with any content. This will be always executed, but if an error occurs during that, all output from this block is rolled back, and the recover block will be executed.
  • recover block: Template block with any content. This will be executed only if there was an error during the execution of the attempt block. You may print an error messages here and such.

The recover is mandatory. attempt/recover can be nested freely into other attempt blocks or recover blocks.

Note:

The format shown here is supported starting from 2.3.3; earlier it was <#attempt>...<#recover>...</#recover>, which is still supported for backward compatibility. Furthermore, these directives were introduced with FreeMarker 2.3.1, so they aren't exist in 2.3.

Description

These directives are used if you want the page successfully outputted even if the outputting of a certain part of the page fails. If an error occurs during the execution of the attempt block, then the output of the attempt block is rolled back (and the error is logged, with the default configuration at least), and the recover block is executed instead, then template execution continues normally after the recover block. If no error occurs during the execution of the attempt block, then the recover block is ignored. A simple example:

Template
Primary content
<#attempt>
  Optional content: ${thisMayFails}
<#recover>
  Ops! The optional content is not available.
</#attempt>
Primary content continued

If the thisMayFails variable doesn't exist (or any other error occurs at that place), then the output is:

Output
Primary content
  Ops! The optional content is not available.
Primary content continued

If the thisMayFails variable exists and it's value is 123, then the output is:

Output
Primary content
  Optional content: 123
Primary content continued

The attempt block has an all-or-none semantic: either the entire content of the attempt block is output (when there was no error), or no output at all results from the execution of the attempt block (when there was an error). For example, above, the failure happens after "Optional content: " was printed, still it is not there in the output before the "Ops!". (This is implemented with the aggressive buffering of the output inside the attempt block. Not even the flush directive will send the output to the client.)

To prevent misunderstandings coming from the above example: attempt/recover is not (only) for handling undefined variables (for that use missing value handler operators). It can handle all kind of errors that occurs when the block is executed (i.e. not syntactical errors, which are detected earlier). It meant to enclose bigger template fragments, where error can occur at various points. For example, you have a part in your template that deals with printing advertisements, but that's not the primary content of the page, so you don't want your whole page be down just because some error occurs with the printing of the advertisements (say, because of a database server outage). So you put the whole advertisement printing into an attempt block.

In some environments programmers configure FreeMarker so that it doesn't abort template execution for certain errors, but continues execution, possibly after printing some error indicator to the output (see more here...). The attempt directive doesn't consider such suppressed errors as errors.

Inside a recover block the error message of the error is available with the error special variable. Don't forget that references to special variable are started with dot (for example: ${.error}).

By default errors occurring inside an attempt block are logged with ERROR level, despite that the template recovers from them. This is because attempt is not meant to be a general purpose error handler mechanism, like try is in Java. It's for decreasing the impact of unexpected errors on the visitors, by making it possible that only part of the page is going down, instead of the whole page. But it's still an error, something that needs the attention of the operators. (The way this error is reported can be customized with the attempt_exception_reporter configuration setting, since FreeMarker 2.3.27.)