{"record":{"id":"ab458ced7bd87826","repo":"docker/cli","slug":"failed-to-cast-to-expected-type-w","errorCode":null,"errorMessage":"failed to cast to expected type: %w","messagePattern":"failed to cast to expected type: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/compose/interpolation/interpolation.go","lineNumber":71,"sourceCode":"\t}\n\n\treturn out, nil\n}\n\nfunc recursiveInterpolate(value any, path Path, opts Options) (any, error) {\n\tswitch value := value.(type) {\n\tcase string:\n\t\tnewValue, err := opts.Substitute(value, template.Mapping(opts.LookupValue))\n\t\tif err != nil || newValue == value {\n\t\t\treturn value, newPathError(path, err)\n\t\t}\n\t\tcaster, ok := opts.getCasterForPath(path)\n\t\tif !ok {\n\t\t\treturn newValue, nil\n\t\t}\n\t\tcasted, err := caster(newValue)\n\t\tif err != nil {\n\t\t\treturn casted, newPathError(path, fmt.Errorf(\"failed to cast to expected type: %w\", err))\n\t\t}\n\t\treturn casted, nil\n\n\tcase map[string]any:\n\t\tout := map[string]any{}\n\t\tfor key, elem := range value {\n\t\t\tinterpolatedElem, err := recursiveInterpolate(elem, path.Next(key), opts)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tout[key] = interpolatedElem\n\t\t}\n\t\treturn out, nil\n\n\tcase []any:\n\t\tout := make([]any, len(value))\n\t\tfor i, elem := range value {\n\t\t\tinterpolatedElem, err := recursiveInterpolate(elem, path.Next(PathMatchList), opts)","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/docker/cli/blob/4f84911bfe8811e9b028e4b1fee8e7510be79387/cli/compose/interpolation/interpolation.go#L53-L89","documentation":"Returned by recursiveInterpolate after a value was substituted but the path's registered caster failed to convert the resulting string to its target type (interpolation.go:69-71). The TypeCastMapping (e.g. toInt, toFloat, toBoolean) runs on fields like deploy.replicas or healthcheck.retries; a non-numeric/non-boolean interpolated value is rejected.","triggerScenarios":"An interpolated compose value that must be int/float/bool ends up non-convertible after substitution, e.g. deploy.replicas: ${REPLICAS} with REPLICAS=auto, or healthcheck.retries set to a non-numeric env value. The caster error is wrapped at interpolation.go:71.","commonSituations":"Env var holding a typo or empty/non-numeric string; a variable reused across fields where the value is text; casting a boolean field to something other than yes/no/true/false/on/off.","solutions":["Set the environment variable to a valid value for the field's expected type (integer for replicas/ports, float for max_failure_ratio, yes/no/true/false/on/off for booleans).","Provide a default in the template, e.g. ${REPLICAS:-2}, so an unset/empty var still casts.","Check the unwrapped inner error (strconv.Atoi / ParseFloat / toBoolean) to see which value failed."],"exampleFix":"# before\nenvironment:\n  REPLICAS: auto\ndeploy:\n  replicas: ${REPLICAS}\n# after\nenvironment:\n  REPLICAS: \"3\"\ndeploy:\n  replicas: ${REPLICAS:-3}","handlingStrategy":"validation","validationCode":"// Validate interpolated values against their expected cast before handing the config to the loader.\nvar intPaths = []string{\"deploy.replicas\", \"healthcheck.retries\"}\nfunc assertInt(name, val string) error {\n    if _, err := strconv.Atoi(val); err != nil {\n        return fmt.Errorf(\"%s must be an integer, got %q\", name, val)\n    }\n    return nil\n}\n// if v := os.Getenv(\"REPLICAS\"); v != \"\" { if err := assertInt(\"REPLICAS\", v); err != nil { return err } }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Provide defaults in templates (${VAR:-2}) so unset vars still cast.","Ensure env vars for numeric/boolean fields hold valid values.","Inspect the unwrapped inner error (strconv.Parse*) to see which value failed."],"tags":["compose","interpolation","type-cast","env"],"backgroundTag":null,"analyzedSha":"4f84911bfe8811e9b028e4b1fee8e7510be79387","analyzedAt":"2026-08-07T12:15:29.814Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}