{"record":{"id":"4961c581e8f4c45d","repo":"netbirdio/netbird","slug":"invalid-duration-format-v","errorCode":null,"errorMessage":"invalid duration format: %v","messagePattern":"invalid duration format: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"client/cmd/debug.go","lineNumber":235,"sourceCode":"\t\t//nolint\n\t\treturn fmt.Errorf(\"unknown log level: %s. Available levels are: panic, fatal, error, warn, info, debug, trace\\n\", args[0])\n\t}\n\n\t_, err = client.SetLogLevel(cmd.Context(), &proto.SetLogLevelRequest{\n\t\tLevel: level,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to set log level: %v\", status.Convert(err).Message())\n\t}\n\n\tcmd.Println(\"Log level set successfully to\", args[0])\n\treturn nil\n}\n\nfunc runForDuration(cmd *cobra.Command, args []string) error {\n\tduration, err := time.ParseDuration(args[0])\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid duration format: %v\", err)\n\t}\n\n\tanonymizeEnabled, anonymizeLevel, err := effectiveAnonymize()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconn, err := getClient(cmd)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer func() {\n\t\tif err := conn.Close(); err != nil {\n\t\t\tlog.Errorf(errCloseConnection, err)\n\t\t}\n\t}()\n\n\tclient := proto.NewDaemonServiceClient(conn)","sourceCodeStart":217,"sourceCodeEnd":253,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/cmd/debug.go#L217-L253","documentation":"runForDuration parses its first positional argument with time.ParseDuration and wraps failure here. Go duration strings require a unit suffix and use specific abbreviations: '30s', '5m', '1h30m', '500ms' are valid; '30' (no unit), '1min', '1hr', '1 sec' (space), '1h.5m', or a comma are not. This is pure client-side validation before anything is sent to the daemon.","triggerScenarios":"netbird debug up --run-for 30 (missing unit); '10min' instead of '10m'; '1 hr' with a space splitting into two args; locale habits like '1,5h' comma decimal; a shell variable that is empty or contains whitespace.","commonSituations":"Scripts building the duration from numbers without appending a unit; users expecting cron-style or natural-language durations; copy-pasting values from tools that accept bare seconds.","solutions":["Append a Go unit: s (seconds), m (minutes), h (hours) — e.g. 90s, 5m, 2h; combine like 1h30m","Avoid spaces inside the value; quote it if it comes from a variable: netbird debug up --run-for \"${d}\"","If sourcing the value from humans, validate/normalize it in the script first (e.g. append 's' when it is a bare number)"],"exampleFix":"# before\nnetbird debug up --run-for 30\n# -> invalid duration format: ...\n\n# after\nnetbird debug up --run-for 30s","handlingStrategy":"validation","validationCode":"// Validate before invoking the CLI:\nif _, err := time.ParseDuration(val); err != nil {\n    return fmt.Errorf(\"invalid duration %q (need Go syntax like 30s, 5m, 1h30m)\", val)\n}","typeGuard":"// Guard for bare numbers coming from config/users — promote to seconds:\nfunc normalizeDuration(s string) (time.Duration, error) {\n    if d, err := time.ParseDuration(s); err == nil {\n        return d, nil\n    }\n    if n, err := strconv.Atoi(s); err == nil {\n        return time.Duration(n) * time.Second, nil\n    }\n    return 0, fmt.Errorf(\"invalid duration %q\", s)\n}","tryCatchPattern":null,"preventionTips":["Always append a Go unit (s/m/h); remember m means minutes, not seconds","Quote duration variables to prevent shell splitting on spaces","Reject locale forms (commas, 'min'/'hr' suffixes) at input boundaries"],"tags":["cli","validation","duration","parsing","time"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}