{"record":{"id":"9aaac545d308d582","repo":"XTLS/Xray-core","slug":"invalid-duration-v","errorCode":null,"errorMessage":"invalid duration: %v","messagePattern":"invalid duration: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"infra/conf/cfgcommon/duration/duration.go","lineNumber":33,"sourceCode":"}\n\n// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON\nfunc (d *Duration) UnmarshalJSON(b []byte) error {\n\tvar v interface{}\n\tif err := json.Unmarshal(b, &v); err != nil {\n\t\treturn err\n\t}\n\tswitch value := v.(type) {\n\tcase string:\n\t\tvar err error\n\t\tdr, err := time.ParseDuration(value)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t*d = Duration(dr)\n\t\treturn nil\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid duration: %v\", v)\n\t}\n}\n","sourceCodeStart":15,"sourceCodeEnd":36,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/infra/conf/cfgcommon/duration/duration.go#L15-L36","documentation":"Duration.UnmarshalJSON accepts only a JSON string parseable by time.ParseDuration (e.g. \"300ms\", \"1m30s\"). The default branch fires when the JSON value is any other type — a bare number, boolean, null, array, or object — and reports the received Go value with %v.","triggerScenarios":"Writing \"idleTimeout\": 300 or \"interval\": 5 instead of \"300s\"/\"5m\" anywhere a cfgcommon.Duration field is configured (health checks, policy buffer sizes/timeouts, transport keep-alive intervals, etc.).","commonSituations":"Muscle memory from configs where numeric seconds are accepted; JSON generators emitting numbers; migrating configs from tools that allow bare integers for durations.","solutions":["Find the field named in the surrounding parse error and quote its value as a duration string with an explicit unit","Use supported units: ns, us/µs, ms, s, m, h (composable, e.g. \"1m30s\")","Do not use bare numbers — \"5\" alone is invalid even quoted","Lint JSON configs for numeric values in known duration fields before deploy"],"exampleFix":"// before\n\"healthCheck\": { \"interval\": 5, \"idleTimeout\": 300 }\n\n// after\n\"healthCheck\": { \"interval\": \"5s\", \"idleTimeout\": \"300s\" }","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"// JSON Schema-style guard for duration fields: must be a string with a unit\nconst durationRe = /^\\d+(ns|us|µs|ms|s|m|h)+$/;\nfunction isDurationString(v) {\n  return typeof v === \"string\" && durationRe.test(v);\n}\n// assert isDurationString(cfg.healthCheck.interval) before writing config","tryCatchPattern":null,"preventionTips":["Always quote durations with explicit units (\"5s\", \"1m30s\")","Never emit bare numbers for duration fields from generators","Add a JSON schema check for known duration keys in CI"],"tags":["config","json","duration","parsing"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}