hashicorp/terraform · error

attribute schema is nil

Error message

attribute schema is nil

What it means

Raised by Attribute.InternalValidate when called on a nil *Attribute receiver. This is the public entry point at internal_validate.go:131; a nil receiver means the caller asked to validate an attribute that was never constructed.

Source

Thrown at internal/configs/configschema/internal_validate.go:133

				multiErr = errors.Join(multiErr, fmt.Errorf("%s%s: Computed cannot be used when MinItems > 0", prefix, name))
			}
		default:
			multiErr = errors.Join(multiErr, fmt.Errorf("%s%s: invalid nesting mode %s", prefix, name, blockS.Nesting))
		}

		subPrefix := prefix + name + "."
		multiErr = errors.Join(multiErr, blockS.Block.internalValidate(subPrefix))
	}

	return multiErr
}

// InternalValidate returns an error if the receiving attribute and its child
// schema definitions have any inconsistencies with the documented rules for
// valid schema.
func (a *Attribute) InternalValidate(name string) error {
	if a == nil {
		return fmt.Errorf("attribute schema is nil")
	}
	return a.internalValidate(name, "")
}

func (a *Attribute) internalValidate(name, prefix string) error {
	var err error

	/* FIXME: this validation breaks certain existing providers and cannot be enforced without coordination.
	if !validName.MatchString(name) {
		err = errors.Join(err, fmt.Errorf("%s%s: name may contain only lowercase letters, digits and underscores", prefix, name))
	}
	*/
	if !a.Optional && !a.Required && !a.Computed {
		err = errors.Join(err, fmt.Errorf("%s%s: must set Optional, Required or Computed", prefix, name))
	}
	if a.Optional && a.Required {
		err = errors.Join(err, fmt.Errorf("%s%s: cannot set both Optional and Required", prefix, name))
	}

View on GitHub (pinned to c9def3e214)

Solutions

  1. Guard the call site: if attr != nil { attr.InternalValidate(name) }.
  2. Fix the upstream construction so the *Attribute is always populated before validation.
  3. Prefer validating the whole Block via Block.InternalValidate, which already skips nil entries with a clearer per-name message (error 838).

Example fix

// before
attr := attrs[key]   // nil if absent
if err := attr.InternalValidate(key); err != nil { return err }

// after
attr, ok := attrs[key]
if !ok || attr == nil { continue }
if err := attr.InternalValidate(key); err != nil { return err }
Defensive patterns

Strategy: type-guard

Validate before calling

if attr == nil {
    return fmt.Errorf("attribute %q is nil before validate", name)
}
return attr.InternalValidate(name)

Type guard

func isNonNilAttribute(a *configschema.Attribute) bool { return a != nil }

Prevention

When it happens

Trigger: Code calls someAttr.InternalValidate(name) where someAttr is a nil *Attribute. The nil check at line 132 returns the error before any field access.

Common situations: Lookups like attrs["missing_key"] returning nil and being validated without a nil check; refactoring that moved attribute construction into a helper returning nil on an error path; deserialization producing nil pointers for omitted keys.

Related errors


AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07). Data as JSON: /api/errors/f7523de60768a7a5. Report an issue: GitHub.