Blog · programming

ACF Blocks – “Cannot redeclare” fatal error when saving in Gutenberg

2026-07-23

Symptom – 500 error when saving in Gutenberg

You’re writing an ACF block, you add a helper function – everything runs smoothly on the frontend. You go to the Gutenberg editor, click “Update” and you get:

PHP Fatal error: Cannot redeclare authors_picker_split_bio()
(previously declared in .../authors-picker.php:44)

The page returns 500 Internal Server Error, the editor UI shows “Updating failed”. The frontend? Working fine. The code? Looks correct.

Gutenberg error message 'Updating failed' - PHP fatal error Cannot redeclare when saving an ACF block
The classic “Updating failed” view in Gutenberg.

Why this happens

WordPress renders the same ACF block template multiple times in one request:

  • Once – preview in Gutenberg editor (via REST API)
  • Second time – server-side render on save
  • Third time – if you use InnerBlocks or repeats

On the frontend, the template loads once so there’s no problem. But in Gutenberg the second include causes a fatal error, because PHP doesn’t allow declaring a function with the same name twice.

Fix – if(!function_exists) guard

Every helper function defined inside an ACF block file (typically lib/blocks/block-name.php) needs to be wrapped in a guard:

if (!function_exists('my_helper_function')) {
    function my_helper_function($arg) {
        // function logic
        return $result;
    }
}

The guard checks if the function already exists – if so, it simply skips the declaration. The second include of the same block doesn’t crash.

What you don’t need to wrap

The rule applies only to named global functions. You don’t need to wrap:

  • Anonymous functions (closures) in add_action / add_filter
  • Class methods (classes have their own guard via class_exists)
  • Variables and constants

So this code is safe without a guard:

add_filter('the_content', function($content) {
    return $content . '<p>appendix</p>';
});

Cleaner alternative – move functions outside the template

Instead of wrapping every function in a guard, you can extract them from the block file to a separate helper file, included once via functions.php:

// functions.php
require_once get_template_directory() . '/lib/helpers/blocks-helpers.php';

// lib/helpers/blocks-helpers.php
function my_helper_function($arg) {
    // logic
}

Then the block template just calls my_helper_function() without declaring. This is cleaner if the function is used by more than one block. For functions tightly coupled to a single block – in-place guard is fine.

How to catch this before it hits production

The fatal error only appears when saving in Gutenberg, so it’s easy to miss. Test like this:

  1. Write a new block or add a helper function
  2. Go to the editor of a page where this block is used
  3. Click Update – if you get “Updating failed” and the network console shows 500, that’s it
  4. Check WordPress debug.log – the specific function name will be there

Summary

One simple rule: every named function in an ACF block file goes into an if(!function_exists()) guard. It won’t hurt where it’s not needed, and it saves you where it is.

Alternatively – keep functions outside blocks, in separate helpers. But that requires discipline; in-place guard is defensive and more forgiving.

Back to all posts

Got a project to talk about?

Just tell me what you need - it does not have to be technical, that is my job. I will get back to you and tell you straight whether and how I can help.