hyperledger/fabric · error

invalid duration

Error message

invalid duration

What it means

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.

Source

Thrown at core/container/externalbuilder/instance.go:59

}

func (d *Duration) UnmarshalJSON(b []byte) error {
	var v any
	if err := json.Unmarshal(b, &v); err != nil {
		return err
	}

	switch value := v.(type) {
	case float64:
		*d = Duration(time.Duration(value))
	case string:
		dur, err := time.ParseDuration(value)
		if err != nil {
			return err
		}
		*d = Duration(dur)
	default:
		return errors.New("invalid duration")
	}

	return nil
}

// ChaincodeServerUserData holds "connection.json" information
type ChaincodeServerUserData struct {
	Address            string   `json:"address"`
	Domain             string   `json:"domain"`
	DialTimeout        Duration `json:"dial_timeout"`
	TLSRequired        bool     `json:"tls_required"`
	ClientAuthRequired bool     `json:"client_auth_required"`
	ClientKey          string   `json:"client_key"`  // PEM encoded client key
	ClientCert         string   `json:"client_cert"` // PEM encoded client certificate
	RootCert           string   `json:"root_cert"`   // PEM encoded peer chaincode certificate
}

func (c *ChaincodeServerUserData) ChaincodeServerInfo(cryptoDir string) (*ccintf.ChaincodeServerInfo, error) {

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Set the duration field to a valid string like "5s" or "500ms"
  2. Or set it to a bare JSON number, which is interpreted as seconds
  3. Validate connection.json against the expected schema before the builder emits it

Example fix

// before
{"dial_timeout": {"seconds": 5}}
// after
{"dial_timeout": "5s"}
Defensive patterns

Strategy: validation

Validate before calling

func validJSONDuration(raw json.RawMessage) error {
    var s string
    if err := json.Unmarshal(raw, &s); err == nil {
        _, perr := time.ParseDuration(s)
        return perr
    }
    var n float64
    if err := json.Unmarshal(raw, &n); err == nil { return nil }
    return errors.New("invalid duration")
}

Try / catch

var d eb.Duration
if err := json.Unmarshal(raw, &d); err != nil {
    return fmt.Errorf("duration field must be like \"5s\" or seconds number: %w", err)
}

Prevention

When it happens

Trigger: Deserializing runConfig/connection.json user data where a duration field (e.g. dial_timeout) is set to a non-string, non-numeric JSON value.

Common situations: 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.

Related errors


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/29ef41c22c22c32d. Report an issue: GitHub.