{"record":{"id":"6a2c9aab22eaa7c6","repo":"hashicorp/packer","slug":"can-t-tell-if-interpolation-is-done-s","errorCode":null,"errorMessage":"Can't tell if interpolation is done: %s","messagePattern":"Can't tell if interpolation is done: (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packer/core.go","lineNumber":906,"sourceCode":"\t\t\t\t\t\"required variable not set: %s\", n))\n\t\t\t}\n\t\t}\n\t}\n\n\t// TODO: validate all builders exist\n\t// TODO: ^^ provisioner\n\t// TODO: ^^ post-processor\n\n\treturn err\n}\n\nfunc isDoneInterpolating(v string) (bool, error) {\n\t// Check for whether the var contains any more references to `user`, wrapped\n\t// in interpolation syntax.\n\tfilter := `{{\\s*user\\s*\\x60.*\\x60\\s*}}`\n\tmatched, err := regexp.MatchString(filter, v)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"Can't tell if interpolation is done: %s\", err)\n\t}\n\tif matched {\n\t\t// not done interpolating; there's still a call to \"user\" in a template\n\t\t// engine\n\t\treturn false, nil\n\t}\n\t// No more calls to \"user\" as a template engine, so we're done.\n\treturn true, nil\n}\n\nfunc (c *Core) renderVarsRecursively() (*interpolate.Context, error) {\n\tctx := c.Context()\n\tctx.EnableEnv = true\n\tctx.UserVariables = make(map[string]string)\n\tshouldRetry := true\n\tchanged := false\n\tfailedInterpolation := \"\"\n","sourceCodeStart":888,"sourceCodeEnd":924,"githubUrl":"https://github.com/hashicorp/packer/blob/eb36e3c3e48a036f3e8cc94087636ee72e1303c9/packer/core.go#L888-L924","documentation":"`isDoneInterpolating` uses `regexp.MatchString` with a fixed pattern (`{{\\s*user\\s*`.*`\\s*}}`) to decide whether a user variable still contains a `{{user `...`}}` reference. The pattern is a compile-time constant, so in practice this error is nearly unreachable; it fires only if the regexp engine fails to match the string (e.g. pathological input causing a regexp execution error). `renderVarsRecursively` and tests propagate it immediately, aborting variable interpolation.","triggerScenarios":"`isDoneInterpolating(v)` is called from `renderVarsRecursively` (after a successful `interpolate.RenderRegex`) or from `TestIsDoneInterpolating`, and `regexp.MatchString(filter, v)` returns a non-nil error, which is wrapped as `Can't tell if interpolation is done: %s`.","commonSituations":"Extremely rare in practice: regexp engine errors on the fixed pattern are essentially impossible with normal variable values; would indicate an internal/runtime-level issue rather than user misconfiguration. Most likely encountered by SDK/plugin developers touching the regex or running unit tests.","solutions":["Read the wrapped inner error to identify why regexp.MatchString failed; it is not a template syntax problem.","Retry the command once — regexp execution errors on fixed patterns are not expected to be deterministic user-facing failures.","If reproducible, report it as a bug with the offending variable value; the pattern is a constant in packer/core.go and should never error."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Go: propagate but recognize as internal\nif err := core.Initialize(); err != nil {\n    if strings.Contains(err.Error(), \"Can't tell if interpolation is done\") {\n        return fmt.Errorf(\"internal interpolation check failed: %w\", err)\n    }\n    return err\n}","preventionTips":["This is effectively an internal invariant failure; report it upstream if you hit it.","Do not modify the interpolation regex in forks without testing against `TestIsDoneInterpolating` cases.","Keep variable values free of pathological input that could stress the regexp engine."],"tags":["packer","interpolation","regexp"],"backgroundTag":"regexp-compile-error","analyzedSha":"eb36e3c3e48a036f3e8cc94087636ee72e1303c9","analyzedAt":"2026-09-05T13:20:43.127Z","contentChangedAt":"2026-09-05T13:20:43.127Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}