hashicorp/packer · error

malformed datasource reference %q, data sources must be comp

Error message

malformed datasource reference %q, data sources must be composed of 3 parts

What it means

newDataSourceRefString handles the 'data.*' branch of NewRefString and requires exactly three dot-separated segments: data.<type>.<name>. This error is thrown when a datasource reference has the right prefix ('data') but the wrong number of segments, so the datasource type and/or name cannot be identified.

Source

Thrown at hcl2template/types.refstring.go:79

		}, nil
	case "data":
		return newDataSourceRefString(parts)
	}

	return refString{}, fmt.Errorf("unsupported reftype %q, must be either 'data', 'local' or 'var'", parts[0])
}

func (rs refString) String() string {
	if rs.Type == "" {
		return fmt.Sprintf("%s.%s", rs.MType, rs.Name)
	}

	return fmt.Sprintf("%s.%s.%s", rs.MType, rs.Type, rs.Name)
}

func newDataSourceRefString(parts []string) (refString, error) {
	if len(parts) != 3 {
		return refString{}, fmt.Errorf("malformed datasource reference %q, data sources must be composed of 3 parts",
			strings.Join(parts, "."))
	}

	return refString{
		MType: "data",
		Type:  parts[1],
		Name:  parts[2],
	}, nil
}

// getComponentByRef gets a registered component from the configuration from a refString
func (cfg *PackerConfig) getComponentByRef(rs refString) (interface{}, error) {
	switch rs.MType {
	case "data":
		for _, ds := range cfg.Datasources {
			if ds.Type != rs.Type {
				continue
			}

View on GitHub (pinned to eb36e3c3e4)

Solutions

  1. Use the full three-part form: data.<datasource-type>.<datasource-name>, e.g. data.amazon-ami.my_ami.
  2. If you need an output field of the datasource, reference the specific attribute after resolving the block, not inside the refString itself.
  3. Count the dots: exactly two dots are required in a data.* reference.
  4. If the type label is unknown, check the datasource plugin name in the template's required_plugins block and use that as <type>.

Example fix

// before
rs, err := NewRefString("data.my_ami")
// after
rs, err := NewRefString("data.amazon-ami.my_ami")
Defensive patterns

Strategy: validation

Validate before calling

func validDataSourceRef(s string) bool {
	parts := strings.Split(s, ".")
	return len(parts) == 3 && parts[0] == "data"
}
// guard before: NewRefString("data.amazon-ami.my_ami")

Type guard

func isThreePartDataRef(s string) bool {
	parts := strings.Split(s, ".")
	return len(parts) == 3 && parts[0] == "data" && parts[1] != "" && parts[2] != ""
}

Try / catch

rs, err := NewRefString(ref)
if err != nil {
	return fmt.Errorf("malformed data source ref %q (need data.<type>.<name>): %w", ref, err)
}

Prevention

When it happens

Trigger: Calling NewRefString with 'data.<name>' (2 parts, type missing), 'data.<type>' alone, 'data.<type>.<name>.<extra>' (4+ parts), or bare 'data' (1 part).

Common situations: Writing ${data.my_ami} in a template instead of ${data.amazon-ami.my_ami}; copy-pasting a var/local style two-part reference for a datasource; accidentally appending an attribute like data.amazon-ami.my_ami.id into a context that expects only the block reference.

Understand the failure class

Related errors


AI-assisted analysis of hashicorp/packer@eb36e3c3e4 (2026-09-05). Data as JSON: /api/errors/fb76c3e9824f1211. Report an issue: GitHub.