{"record":{"id":"6bc5cd145004e734","repo":"netbirdio/netbird","slug":"expiration-must-be-a-positive-duration-e-g-72","errorCode":null,"errorMessage":"--expiration must be a positive duration (e.g., 720h, 365d, 8760h)","messagePattern":"--expiration must be a positive duration \\(e\\.g\\., 720h, 365d, 8760h\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/cmd/signer/artifactkey.go","lineNumber":32,"sourceCode":"\tbundlePubKeysRootPrivKeyFile string\n\tbundlePubKeysPubKeyFiles     []string\n\tbundlePubKeysFile            string\n\n\tcreateArtifactKeyRootPrivKeyFile string\n\tcreateArtifactKeyPrivKeyFile     string\n\tcreateArtifactKeyPubKeyFile      string\n\tcreateArtifactKeyExpiration      time.Duration\n)\n\nvar createArtifactKeyCmd = &cobra.Command{\n\tUse:   \"create-artifact-key\",\n\tShort: \"Create a new artifact signing key\",\n\tLong: `Generate a new artifact signing key pair signed by the root private key.\nThe artifact key will be used to sign software artifacts/updates.`,\n\tSilenceUsage: true,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tif createArtifactKeyExpiration <= 0 {\n\t\t\treturn fmt.Errorf(\"--expiration must be a positive duration (e.g., 720h, 365d, 8760h)\")\n\t\t}\n\n\t\tif err := handleCreateArtifactKey(cmd, createArtifactKeyRootPrivKeyFile, createArtifactKeyPrivKeyFile, createArtifactKeyPubKeyFile, createArtifactKeyExpiration); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create artifact key: %w\", err)\n\t\t}\n\t\treturn nil\n\t},\n}\n\nvar bundlePubKeysCmd = &cobra.Command{\n\tUse:   \"bundle-pub-keys\",\n\tShort: \"Bundle multiple artifact public keys into a signed package\",\n\tLong: `Bundle one or more artifact public keys into a signed package using the root private key.\nThis command is typically used to distribute or authorize a set of valid artifact signing keys.`,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tif len(bundlePubKeysPubKeyFiles) == 0 {\n\t\t\treturn fmt.Errorf(\"at least one --artifact-pub-key-file must be provided\")\n\t\t}","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/cmd/signer/artifactkey.go#L14-L50","documentation":"create-artifact-key validates that --expiration is a strictly positive Go duration. The flag defaults to 0 and is marked required, so omitting it, passing zero, or a negative duration trips this guard before any key material is touched.","triggerScenarios":"Omitting --expiration; --expiration 0 or --expiration=-1h; also note cobra's DurationVar rejects units like '365d' at parse time, so only hour/minute/second syntax reaches this check.","commonSituations":"Copy-pasting the '365d' example from the message into the flag; scripting the signer tool without setting every required flag.","solutions":["Pass a positive Go duration: --expiration 720h (about 30 days) or --expiration 8760h (one year)","Convert day units to hours: 365d equals 8760h","Ensure scripts always set the flag (it is required)"],"exampleFix":"# before\ncreate-artifact-key ... --expiration 365d\n# after\ncreate-artifact-key ... --expiration 8760h","handlingStrategy":"validation","validationCode":"if expiration <= 0 {\n\treturn fmt.Errorf(\"--expiration must be a positive duration (e.g., 720h, 8760h)\")\n}\nif expiration < 24*time.Hour {\n\t// guard against accidentally tiny windows like 720s\n\treturn fmt.Errorf(\"--expiration %s is suspiciously short\", expiration)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pass hour-based durations (8760h for a year)","Never use day units; cobra's DurationVar rejects them before validation runs","Set required flags explicitly in scripts instead of relying on defaults"],"tags":["signing","cli","validation","go"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}