octobercms/october · error · ApplicationException

backend::lang.form.behavior_not_ready

backend::lang.form.behavior_not_ready

Error message

Form behavior has not been initialized, check that you have called initForm() in your controller.

What it means

The Settings controller overrides formRender() to delegate to formWidget->render(). formWidget is only built during the update() flow (findSettingItem -> createModel -> initWidgets). If formRender() is reached before that — typically because update() aborted earlier (e.g. item not found or model missing) yet a view still calls it, or a custom action invokes it directly — backend::lang.form.behavior_not_ready is thrown.

Source

Thrown at modules/system/controllers/Settings.php:161

     */
    public function update_onResetDefault($author, $plugin, $code = null)
    {
        $item = $this->findSettingItem($author, $plugin, $code);
        $model = $this->createModel($item);
        $model->resetDefault();

        Flash::success(Lang::get('backend::lang.form.reset_success'));

        return Backend::redirect('system/settings/update/'.$author.'/'.$plugin.'/'.$code);
    }

    /**
     * formRender renders the form
     */
    public function formRender($options = [])
    {
        if (!$this->formWidget) {
            throw new ApplicationException(Lang::get('backend::lang.form.behavior_not_ready'));
        }

        return $this->formWidget->render($options);
    }

    /**
     * initWidgets prepare the widgets used by this action
     * @param Model $model
     */
    protected function initWidgets($model)
    {
        $config = $model->getFieldConfig();
        $config->model = $model;
        $config->arrayName = class_basename($model);
        $config->context = 'update';

        $widget = $this->makeWidget(\Backend\Widgets\Form::class, $config);
        $widget->bindToController();

View on GitHub (pinned to b608633a7e)

Solutions

  1. Fix the upstream error that aborts update() ('Unable to find the specified settings.' or the missing-model error) — formRender then initializes normally
  2. In custom actions, replicate the update() flow: findSettingItem -> createModel -> initWidgets, then formRender
  3. Guard custom partials so they render the form only when the widget exists

Example fix

// before: custom action renders the form without building the widget
public function mySettings($author, $plugin, $code = null)
{
    return $this->formRender(); // formWidget is null
}

// after
public function mySettings($author, $plugin, $code = null)
{
    if (!$item = $this->findSettingItem($author, $plugin, $code)) {
        throw new ApplicationException(__('Unable to find the specified settings.'));
    }
    $model = $this->createModel($item);
    $this->initWidgets($model);
    return $this->formRender();
}
Defensive patterns

Strategy: type-guard

Validate before calling

// in a custom Settings controller action, before rendering any form partial
if ($this->formWidget === null) {
    // build it: findSettingItem -> createModel -> initWidgets, or skip rendering
}

Prevention

When it happens

Trigger: A custom settings view/partial calling $this->formRender() on an error path where initWidgets never ran; an AJAX handler or custom action on the Settings controller rendering the form without first building the widget.

Common situations: Backend view overrides that unconditionally render the form; extensions adding settings actions that skip createModel/initWidgets; the underlying update() error masking itself as this secondary failure.

Related errors


AI-assisted analysis of octobercms/october@b608633a7e (2026-08-21). Data as JSON: /api/errors/5aefc839345e556c. Report an issue: GitHub.