{"record":{"id":"f80d5eadd91d58d8","repo":"hashicorp/packer","slug":"failed-to-interpolate-max-retries-s","errorCode":null,"errorMessage":"failed to interpolate `max_retries`: %s","messagePattern":"failed to interpolate `max_retries`: (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packer/core.go","lineNumber":296,"sourceCode":"\t\t}\n\t}\n\t// If we're pausing, we wrap the provisioner in a special pauser.\n\tif rawP.PauseBefore != 0 {\n\t\tprovisioner = &PausedProvisioner{\n\t\t\tPauseBefore: rawP.PauseBefore,\n\t\t\tProvisioner: provisioner,\n\t\t}\n\t} else if rawP.Timeout != 0 {\n\t\tprovisioner = &TimeoutProvisioner{\n\t\t\tTimeout:     rawP.Timeout,\n\t\t\tProvisioner: provisioner,\n\t\t}\n\t}\n\tmaxRetries := 0\n\tif rawP.MaxRetries != \"\" {\n\t\trenderedMaxRetries, err := interpolate.Render(rawP.MaxRetries, c.Context())\n\t\tif err != nil {\n\t\t\treturn cbp, fmt.Errorf(\"failed to interpolate `max_retries`: %s\", err.Error())\n\t\t}\n\t\tmaxRetries, err = strconv.Atoi(renderedMaxRetries)\n\t\tif err != nil {\n\t\t\treturn cbp, fmt.Errorf(\"`max_retries` must be a valid integer: %s\", err.Error())\n\t\t}\n\t}\n\tif maxRetries != 0 {\n\t\tprovisioner = &RetriedProvisioner{\n\t\t\tMaxRetries:  maxRetries,\n\t\t\tProvisioner: provisioner,\n\t\t}\n\t}\n\n\tif rawP.Type == \"hcp-sbom\" {\n\t\tprovisioner = &SBOMInternalProvisioner{\n\t\t\tProvisioner: provisioner,\n\t\t}\n\t}","sourceCodeStart":278,"sourceCodeEnd":314,"githubUrl":"https://github.com/hashicorp/packer/blob/eb36e3c3e48a036f3e8cc94087636ee72e1303c9/packer/core.go#L278-L314","documentation":"The template sets `max_retries` on a provisioner with a value containing template variables (e.g. `{{env `RETRIES`}}`), and interpolate.Render failed to evaluate it against the core context — usually because the referenced variable/function is unknown or the expression is malformed. Packer aborts building the provisioner.","triggerScenarios":"generateCoreBuildProvisionerWithProvisioner calls interpolate.Render(rawP.MaxRetries, c.Context()) when rawP.MaxRetries != \"\" and Render returns an error: unknown engine variable, missing env var, or invalid template syntax inside the max_retries value.","commonSituations":"Using `{{env `MAX_RETRIES`}}` while the environment variable is not set; referencing a variable that does not exist in a JSON template; HCL2 variables used in a context where they are not defined; typo in function name inside the interpolation.","solutions":["Set the environment/user variables referenced in `max_retries` before running the build (e.g. export MAX_RETRIES=3).","Use `-var`/`-var-file` to supply any missing user variables.","Fix interpolation syntax typos in the max_retries value.","Give `max_retries` a literal integer if interpolation is not needed."],"exampleFix":"// before\n\"max_retries\": \"{{env `RETRIES`}}\"   # RETRIES unset -> render fails\n// after\n$ export RETRIES=3\n// or\n\"max_retries\": \"3\"","handlingStrategy":"validation","validationCode":"// Ensure interpolated inputs exist before building (shell):\n: \"${RETRIES:?RETRIES must be set}\"   # fails fast if unset\n// HCL2: add validation\nvariable \"retries\" {\n  type    = string\n  default = \"0\"\n  validation { condition = can(tonumber(var.retries)); error_message = \"retries must be numeric\" }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Set all env vars referenced by template interpolations in CI before invoking packer.","Prefer HCL2 variables with validation blocks over raw env interpolation.","Use literal integers for max_retries unless dynamic value is required.","Run `packer validate -var ...` with the same variables as the build."],"tags":["provisioner","interpolation","template-variables"],"backgroundTag":"template-interpolation-failed","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"}