netbirdio/netbird · error

--expiration must be a positive duration (e.g., 720h, 365d,

Error message

--expiration must be a positive duration (e.g., 720h, 365d, 8760h)

What it means

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.

Source

Thrown at client/cmd/signer/artifactkey.go:32

	bundlePubKeysRootPrivKeyFile string
	bundlePubKeysPubKeyFiles     []string
	bundlePubKeysFile            string

	createArtifactKeyRootPrivKeyFile string
	createArtifactKeyPrivKeyFile     string
	createArtifactKeyPubKeyFile      string
	createArtifactKeyExpiration      time.Duration
)

var createArtifactKeyCmd = &cobra.Command{
	Use:   "create-artifact-key",
	Short: "Create a new artifact signing key",
	Long: `Generate a new artifact signing key pair signed by the root private key.
The artifact key will be used to sign software artifacts/updates.`,
	SilenceUsage: true,
	RunE: func(cmd *cobra.Command, args []string) error {
		if createArtifactKeyExpiration <= 0 {
			return fmt.Errorf("--expiration must be a positive duration (e.g., 720h, 365d, 8760h)")
		}

		if err := handleCreateArtifactKey(cmd, createArtifactKeyRootPrivKeyFile, createArtifactKeyPrivKeyFile, createArtifactKeyPubKeyFile, createArtifactKeyExpiration); err != nil {
			return fmt.Errorf("failed to create artifact key: %w", err)
		}
		return nil
	},
}

var bundlePubKeysCmd = &cobra.Command{
	Use:   "bundle-pub-keys",
	Short: "Bundle multiple artifact public keys into a signed package",
	Long: `Bundle one or more artifact public keys into a signed package using the root private key.
This command is typically used to distribute or authorize a set of valid artifact signing keys.`,
	RunE: func(cmd *cobra.Command, args []string) error {
		if len(bundlePubKeysPubKeyFiles) == 0 {
			return fmt.Errorf("at least one --artifact-pub-key-file must be provided")
		}

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Pass a positive Go duration: --expiration 720h (about 30 days) or --expiration 8760h (one year)
  2. Convert day units to hours: 365d equals 8760h
  3. Ensure scripts always set the flag (it is required)

Example fix

# before
create-artifact-key ... --expiration 365d
# after
create-artifact-key ... --expiration 8760h
Defensive patterns

Strategy: validation

Validate before calling

if expiration <= 0 {
	return fmt.Errorf("--expiration must be a positive duration (e.g., 720h, 8760h)")
}
if expiration < 24*time.Hour {
	// guard against accidentally tiny windows like 720s
	return fmt.Errorf("--expiration %s is suspiciously short", expiration)
}

Prevention

When it happens

Trigger: 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.

Common situations: Copy-pasting the '365d' example from the message into the flag; scripting the signer tool without setting every required flag.

Related errors


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/6bc5cd145004e734. Report an issue: GitHub.