{"record":{"id":"f9f7a4073d11c984","repo":"docker/cli","slug":"invalid-type-t-for-duration","errorCode":null,"errorMessage":"invalid type %T for duration","messagePattern":"invalid type %T for duration","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/compose/loader/loader.go","lineNumber":915,"sourceCode":"\tswitch value := value.(type) {\n\tcase int:\n\t\treturn int64(value), nil\n\tcase string:\n\t\treturn units.RAMInBytes(value)\n\t}\n\tpanic(fmt.Errorf(\"invalid type for size %T\", value))\n}\n\nvar transformStringToDuration TransformerFunc = func(value any) (any, error) {\n\tswitch value := value.(type) {\n\tcase string:\n\t\td, err := time.ParseDuration(value)\n\t\tif err != nil {\n\t\t\treturn value, err\n\t\t}\n\t\treturn types.Duration(d), nil\n\tdefault:\n\t\treturn value, fmt.Errorf(\"invalid type %T for duration\", value)\n\t}\n}\n\nfunc toServicePortConfigs(value string) ([]any, error) {\n\t// short syntax ([ip:]public:private[/proto])\n\t//\n\t// TODO(thaJeztah): we need an equivalent that handles the \"ip-address\" part without depending on the nat package.\n\tports, portBindings, err := nat.ParsePortSpecs([]string{value})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// We need to sort the key of the ports to make sure it is consistent\n\tkeys := make([]string, 0, len(ports))\n\tfor port := range ports {\n\t\tkeys = append(keys, string(port))\n\t}\n\tsort.Strings(keys)\n","sourceCodeStart":897,"sourceCodeEnd":933,"githubUrl":"https://github.com/docker/cli/blob/4f84911bfe8811e9b028e4b1fee8e7510be79387/cli/compose/loader/loader.go#L897-L933","documentation":"Thrown by transformStringToDuration for duration fields (e.g. `healthcheck.interval`, `restart_policy.delay`, deploy update/rollback timings). The value MUST be a string parseable by time.ParseDuration; ints, bools, or maps are rejected. (Note: a string that fails to parse returns a separate time.ParseDuration error, not this one.)","triggerScenarios":"A duration field is set to a bare number (`interval: 30`) or a map instead of a quoted duration string.","commonSituations":"Writing `interval: 30` instead of `interval: 30s`; YAML treating an unquoted value as a non-string type.","solutions":["Quote a duration string with units: `interval: 30s`, `timeout: 1m`.","Ensure env interpolation yields a string with units, not a bare integer."],"exampleFix":"# before\nweb:\n  healthcheck:\n    interval: 30\n# after\nweb:\n  healthcheck:\n    interval: 30s","handlingStrategy":"type-guard","validationCode":"func validateDuration(field string, v any) error {\n    s, ok := v.(string)\n    if !ok {\n        return fmt.Errorf(\"%s must be a duration string, got %T\", field, v)\n    }\n    if _, err := time.ParseDuration(s); err != nil {\n        return fmt.Errorf(\"%s: %w\", field, err)\n    }\n    return nil\n}","typeGuard":"func isDurationString(v any) bool {\n    s, ok := v.(string)\n    if !ok {\n        return false\n    }\n    _, err := time.ParseDuration(s)\n    return err == nil\n}","tryCatchPattern":null,"preventionTips":["Always include units for durations (30s, 1m, 2h).","Quote values produced by env interpolation to keep them strings.","Run `docker compose config` to surface parse errors early."],"tags":["compose","duration","type-mismatch","healthcheck","service"],"backgroundTag":null,"analyzedSha":"4f84911bfe8811e9b028e4b1fee8e7510be79387","analyzedAt":"2026-08-07T12:15:29.814Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}