hashicorp/packer · error

Unsupported component: %q, only vars, locals and datasources

Error message

Unsupported component: %q, only vars, locals and datasources can be fetched by their refString

What it means

getComponentByRef is the terminal fallthrough of the refString resolver: after checking data/local/var cases, if the component was not found in the matching collection (or the MType was somehow something else), it returns this error stating that only vars, locals, and datasources can be fetched by refString. It covers both an unsupported refString type slipping through and a local/var name that has no matching block.

Source

Thrown at hcl2template/types.refstring.go:120

		}
		return nil, fmt.Errorf("failed to get datasource '%s.%s': component unknown", rs.Type, rs.Name)
	case "local":
		for _, loc := range cfg.LocalBlocks {
			if loc.LocalName != rs.Name {
				continue
			}
			return loc, nil
		}
	case "var":
		for _, val := range cfg.InputVariables {
			if val.Name != rs.Name {
				continue
			}
			return val, nil
		}
	}

	return nil, fmt.Errorf("Unsupported component: %q, only vars, locals and datasources can be fetched by their refString", rs)
}

func (ds *DatasourceBlock) RegisterDependency(rs refString) error {
	switch rs.MType {
	case "data", "local":
		ds.Dependencies = append(ds.Dependencies, rs)
	// NOOP: vars are always evaluated beforehand for datasources
	case "var":
	default:
		return fmt.Errorf("unsupported dependency type %q; datasources can only depend on local, var or data.", rs.MType)
	}

	return nil
}

func (loc *LocalBlock) RegisterDependency(rs refString) error {
	switch rs.MType {
	case "data", "local":

View on GitHub (pinned to eb36e3c3e4)

Solutions

  1. Declare the missing local or variable block in the template (e.g. variable "foo" { ... } or locals { foo = ... }).
  2. Check the name for typos and exact casing against the declared block.
  3. If the variable lives in a var-file, pass it with -var-file or -var on the packer build command.
  4. Confirm the reference is meant to be data/local/var; other component types (builders, provisioners, post-processors) cannot be referenced via refString.

Example fix

// before (undeclared variable)
locals { region = var.aws_region }
// after
variable "aws_region" { type = string, default = "us-east-1" }
locals { region = var.aws_region }
Defensive patterns

Strategy: validation

Validate before calling

// verify the referenced local/var is declared before evaluation
name := "aws_region" // from rs.Name
ok := false
for _, v := range cfg.InputVariables {
	if v.Name == name { ok = true; break }
}
for _, l := range cfg.LocalBlocks {
	if l.LocalName == name { ok = true; break }
}
if !ok {
	return fmt.Errorf("local/var %q is not declared in the template", name)
}

Type guard

func hasLocalOrVar(cfg *hcl2template.PackerConfig, name string) bool {
	for _, v := range cfg.InputVariables {
		if v.Name == name { return true }
	}
	for _, l := range cfg.LocalBlocks {
		if l.LocalName == name { return true }
	}
	return false
}

Try / catch

comp, err := cfg.getComponentByRef(rs)
if err != nil {
	return fmt.Errorf("unresolvable reference %s: %w — declare the variable/local block or pass the missing -var/-var-file", rs, err)
}

Prevention

When it happens

Trigger: Calling getComponentByRef with a 'local' refString whose LocalName is absent from cfg.LocalBlocks, or a 'var' refString whose Name is absent from cfg.InputVariables — the switch falls through to the generic error; also any refString reaching here with a non-data/local/var MType.

Common situations: Referencing ${local.foo} or ${var.foo} that was never declared (typo or removed block); referencing a variable defined only in a var-file not passed via -var-file; forgetting to declare an input variable that is used in a local expression.

Related errors


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