{"record":{"id":"9b7a73caee5d87fe","repo":"yiisoft/yii2","slug":"class-formname-cannot-be-empty-for-tabular-in","errorCode":null,"errorMessage":"{class}::formName() cannot be empty for tabular inputs.","messagePattern":"(.+?)::formName\\(\\) cannot be empty for tabular inputs\\.","errorType":"exception","errorClass":"yii\\base\\InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"framework/helpers/BaseHtml.php","lineNumber":2355,"sourceCode":"     * @return string the generated input name\n     * @throws InvalidArgumentException if the attribute name contains non-word characters.\n     */\n    public static function getInputName($model, $attribute)\n    {\n        $formName = $model->formName();\n        if (!preg_match(static::$attributeRegex, $attribute, $matches)) {\n            throw new InvalidArgumentException('Attribute name must contain word characters only.');\n        }\n        $prefix = $matches[1];\n        $attribute = $matches[2];\n        $suffix = $matches[3];\n        if ($formName === '' && $prefix === '') {\n            return $attribute . $suffix;\n        } elseif ($formName !== '') {\n            return $formName . $prefix . \"[$attribute]\" . $suffix;\n        }\n\n        throw new InvalidArgumentException(get_class($model) . '::formName() cannot be empty for tabular inputs.');\n    }\n\n    /**\n     * Converts input name to ID.\n     *\n     * For example, if `$name` is `Post[content]`, this method will return `post-content`.\n     *\n     * @param string $name the input name\n     * @return string the generated input ID\n     * @since 2.0.43\n     */\n    public static function getInputIdByName($name)\n    {\n        $charset = Yii::$app ? Yii::$app->charset : 'UTF-8';\n        $name = mb_strtolower($name, $charset);\n        return str_replace(['[]', '][', '[', ']', ' ', '.', '--'], ['', '-', '-', '', '-', '-', '-'], $name);\n    }\n","sourceCodeStart":2337,"sourceCodeEnd":2373,"githubUrl":"https://github.com/yiisoft/yii2/blob/66f00d18a29b520f85e8e8f1e32d1e7e7b556cac/framework/helpers/BaseHtml.php#L2337-L2373","documentation":"BaseHtml::getInputName() needs a non-empty form name to compose tabular input names like 'Post[0][title]'. If $model->formName() returns '' (as some apps override it to post bare REST fields) and the attribute expression carries a tabular prefix like '[0]title', there is no left-hand anchor for the bracket syntax, so the method throws InvalidArgumentException telling you formName() cannot be empty for tabular inputs.","triggerScenarios":"A model with formName() overridden to return '' used in a tabular form: Html::activeTextInput($model, '[0]name'); GridView/ListView editing multiple rows of a formName-less model; widgets that always generate tabular attribute expressions (e.g. '[]', '[1]field').","commonSituations":"REST-oriented models overriding formName() for cleaner payload keys, later reused in classic tabular ActiveForm rendering; API-first apps growing an admin UI; third-party widgets (multiple-input, collections) that assume a form name exists.","solutions":["Make formName() return a non-empty string (the default returns the class basename) — adjust payload mapping elsewhere if bare keys are needed.","For models that must keep an empty form name, render non-tabular inputs with plain attribute names (no '[i]' prefix).","In API layers, map incoming bare keys to the model explicitly instead of emptying formName().","If both behaviors are needed, use two model classes: one API-facing with empty formName(), one form-facing with the default."],"exampleFix":"// before\nclass InvoiceItem extends \\yii\\base\\Model\n{\n    public function formName() { return ''; } // breaks tabular forms\n}\necho Html::activeTextInput($model, '[0]name');\n\n// after\npublic function formName()\n{\n    return 'InvoiceItem'; // default behavior — tabular inputs work\n}\necho Html::activeTextInput($model, '[0]name');","handlingStrategy":"validation","validationCode":"$formName = $model->formName();\n$isTabular = strpos($attribute, '[') === 0;\nif ($isTabular && $formName === '') {\n    throw new \\InvalidArgumentException(get_class($model) . ' cannot render tabular inputs with an empty formName()');\n}\n$name = \\yii\\helpers\\Html::getInputName($model, $attribute);","typeGuard":null,"tryCatchPattern":"try {\n    $name = \\yii\\helpers\\Html::getInputName($model, '[0]' . $attr);\n} catch (\\yii\\base\\InvalidArgumentException $e) {\n    // fall back to a non-tabular input for formName-less models\n    $name = \\yii\\helpers\\Html::getInputName($model, $attr);\n}","preventionTips":["Do not override formName() to return '' — map bare API keys to attributes explicitly instead.","If bare payloads are required, isolate them in a dedicated API model class; keep form models with default formName().","When adopting tabular widgets (multiple-input/collections), check the model's formName() first."],"tags":["forms","form-name","tabular-input","validation","yii2"],"backgroundTag":"empty-form-name","analyzedSha":"66f00d18a29b520f85e8e8f1e32d1e7e7b556cac","analyzedAt":"2026-08-17T05:17:23.470Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}