{"record":{"id":"49facdcc0109b6c8","repo":"yiisoft/yii2","slug":"attribute-name-must-contain-word-characters-only","errorCode":null,"errorMessage":"Attribute name must contain word characters only.","messagePattern":"Attribute name must contain word characters only\\.","errorType":"exception","errorClass":"yii\\base\\InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"framework/helpers/BaseHtml.php","lineNumber":2274,"sourceCode":"     *\n     * - `[0]content` is used in tabular data input to represent the \"content\" attribute\n     *   for the first model in tabular input;\n     * - `dates[0]` represents the first array element of the \"dates\" attribute;\n     * - `[0]dates[0]` represents the first array element of the \"dates\" attribute\n     *   for the first model in tabular input.\n     *\n     * If `$attribute` has neither prefix nor suffix, it will be returned back without change.\n     * @param string $attribute the attribute name or expression\n     * @return string the attribute name without prefix and suffix.\n     * @throws InvalidArgumentException if the attribute name contains non-word characters.\n     */\n    public static function getAttributeName($attribute)\n    {\n        if (preg_match(static::$attributeRegex, $attribute, $matches)) {\n            return $matches[2];\n        }\n\n        throw new InvalidArgumentException('Attribute name must contain word characters only.');\n    }\n\n    /**\n     * Returns the value of the specified attribute name or expression.\n     *\n     * For an attribute expression like `[0]dates[0]`, this method will return the value of `$model->dates[0]`.\n     * See [[getAttributeName()]] for more details about attribute expression.\n     *\n     * If an attribute value is an instance of [[ActiveRecordInterface]] or an array of such instances,\n     * the primary value(s) of the AR instance(s) will be returned instead.\n     *\n     * @param Model $model the model object\n     * @param string $attribute the attribute name or expression\n     * @return string|array|null the corresponding attribute value\n     * @throws InvalidArgumentException if the attribute name contains non-word characters.\n     */\n    public static function getAttributeValue($model, $attribute)\n    {","sourceCodeStart":2256,"sourceCodeEnd":2292,"githubUrl":"https://github.com/yiisoft/yii2/blob/66f00d18a29b520f85e8e8f1e32d1e7e7b556cac/framework/helpers/BaseHtml.php#L2256-L2292","documentation":"BaseHtml::getAttributeName() strips the tabular prefix/suffix from an attribute expression using Html::$attributeRegex ('/(^|.*\\])([\\w\\.\\+]+)(\\[.*|$)/u'); if the expression does not match — i.e. the attribute part contains characters outside word chars, dot, or plus — it throws InvalidArgumentException. Every active* form helper resolves attribute names through this method, so malformed attribute expressions break form rendering.","triggerScenarios":"Html::activeTextInput($model, 'full name') (space); attribute 'user-name' (hyphen); '[0]' with no attribute name after it; expressions like '[]'; an empty string; attribute names copied from DB columns containing dashes or spaces and forwarded verbatim.","commonSituations":"Dynamic form builders (CMS, EAV/meta fields) rendering user-defined field names; API payloads supplying field names; attributes derived from column names like 'first-name'; localization data accidentally used as attribute names.","solutions":["Sanitize dynamic field names to [A-Za-z0-9_.+] before rendering (e.g. preg_replace('/[^\\w\\.\\+]/', '_', $name)).","Map external/custom field names to safe model attributes through a lookup table instead of forwarding them raw.","Pre-test expressions with preg_match(Html::$attributeRegex, $name) and fall back to a safe default for failures.","Keep virtual attribute names (model methods like getName0) word-char only."],"exampleFix":"// before\necho Html::activeTextInput($model, $dynamicField); // $dynamicField = 'contact e-mail'\n\n// after\n$safeName = preg_replace('/[^\\w\\.\\+]/u', '_', $dynamicField);\necho Html::activeTextInput($model, $safeName);","handlingStrategy":"validation","validationCode":"if (!preg_match(\\yii\\helpers\\Html::$attributeRegex, $attribute)) {\n    throw new \\InvalidArgumentException(\"Unsafe attribute name for form rendering: {$attribute}\");\n}\necho \\yii\\helpers\\Html::activeTextInput($model, $attribute);","typeGuard":"/** True when Html can resolve the attribute expression. @param string $attribute */\nfunction isRenderableAttribute(string $attribute): bool\n{\n    return (bool) preg_match(\\yii\\helpers\\Html::$attributeRegex, $attribute);\n}","tryCatchPattern":"try {\n    $name = \\yii\\helpers\\Html::getAttributeName($attribute);\n} catch (\\yii\\base\\InvalidArgumentException $e) {\n    \\Yii::warning(\"Rejected attribute name '{$attribute}'\", 'forms');\n    $name = preg_replace('/[^\\\\w\\\\.\\\\+]/u', '_', $attribute);\n}","preventionTips":["Whitelist dynamic field names against the model's attributes() / safe attributes list.","Sanitize external field names to word characters before they reach any active* helper.","Keep model attribute names word-char only; use labels for display text.","Cover dynamic form builders with tests feeding hostile names (spaces, dashes, brackets)."],"tags":["forms","attribute-name","validation","html","yii2"],"backgroundTag":"invalid-attribute-name","analyzedSha":"66f00d18a29b520f85e8e8f1e32d1e7e7b556cac","analyzedAt":"2026-08-17T05:17:23.470Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}