{"record":{"id":"29ef41c22c22c32d","repo":"hyperledger/fabric","slug":"invalid-duration","errorCode":null,"errorMessage":"invalid duration","messagePattern":"invalid duration","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/container/externalbuilder/instance.go","lineNumber":59,"sourceCode":"}\n\nfunc (d *Duration) UnmarshalJSON(b []byte) error {\n\tvar v any\n\tif err := json.Unmarshal(b, &v); err != nil {\n\t\treturn err\n\t}\n\n\tswitch value := v.(type) {\n\tcase float64:\n\t\t*d = Duration(time.Duration(value))\n\tcase string:\n\t\tdur, err := time.ParseDuration(value)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t*d = Duration(dur)\n\tdefault:\n\t\treturn errors.New(\"invalid duration\")\n\t}\n\n\treturn nil\n}\n\n// ChaincodeServerUserData holds \"connection.json\" information\ntype ChaincodeServerUserData struct {\n\tAddress            string   `json:\"address\"`\n\tDomain             string   `json:\"domain\"`\n\tDialTimeout        Duration `json:\"dial_timeout\"`\n\tTLSRequired        bool     `json:\"tls_required\"`\n\tClientAuthRequired bool     `json:\"client_auth_required\"`\n\tClientKey          string   `json:\"client_key\"`  // PEM encoded client key\n\tClientCert         string   `json:\"client_cert\"` // PEM encoded client certificate\n\tRootCert           string   `json:\"root_cert\"`   // PEM encoded peer chaincode certificate\n}\n\nfunc (c *ChaincodeServerUserData) ChaincodeServerInfo(cryptoDir string) (*ccintf.ChaincodeServerInfo, error) {","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/container/externalbuilder/instance.go#L41-L77","documentation":"Returned by Duration.UnmarshalJSON when the JSON value for a duration field is neither a number nor a string — e.g. null, bool, or an object. time.ParseDuration failures for strings are passed through; this sentinel covers the remaining type mismatch in connection.json parsing.","triggerScenarios":"Deserializing runConfig/connection.json user data where a duration field (e.g. dial_timeout) is set to a non-string, non-numeric JSON value.","commonSituations":"Hand-edited connection.json with \"dial_timeout\": true or an object; YAML/JSON tooling emitting quoted numbers incorrectly; schema drift between builder output and peer expectations.","solutions":["Set the duration field to a valid string like \"5s\" or \"500ms\"","Or set it to a bare JSON number, which is interpreted as seconds","Validate connection.json against the expected schema before the builder emits it"],"exampleFix":"// before\n{\"dial_timeout\": {\"seconds\": 5}}\n// after\n{\"dial_timeout\": \"5s\"}","handlingStrategy":"validation","validationCode":"func validJSONDuration(raw json.RawMessage) error {\n    var s string\n    if err := json.Unmarshal(raw, &s); err == nil {\n        _, perr := time.ParseDuration(s)\n        return perr\n    }\n    var n float64\n    if err := json.Unmarshal(raw, &n); err == nil { return nil }\n    return errors.New(\"invalid duration\")\n}","typeGuard":null,"tryCatchPattern":"var d eb.Duration\nif err := json.Unmarshal(raw, &d); err != nil {\n    return fmt.Errorf(\"duration field must be like \\\"5s\\\" or seconds number: %w\", err)\n}","preventionTips":["Emit duration fields as strings like \"30s\" or plain numbers (seconds)","Schema-validate connection.json/runConfig before peer consumption","Avoid hand-editing generated JSON; regenerate via the builder release step"],"tags":["json","unmarshal","duration","external-builder"],"backgroundTag":"invalid-json-duration","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}