{"record":{"id":"b19a4603332f4297","repo":"hashicorp/nomad","slug":"keyring-cannot-be-prepublished-and-full-rotated-at","errorCode":null,"errorMessage":"keyring cannot be prepublished and full rotated at the same time","messagePattern":"keyring cannot be prepublished and full rotated at the same time","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/keyring_endpoint.go","lineNumber":56,"sourceCode":"\t\treturn err\n\t}\n\tk.srv.MeasureRPCRate(\"keyring\", structs.RateMetricWrite, args)\n\tif authErr != nil {\n\t\treturn structs.ErrPermissionDenied\n\t}\n\tdefer metrics.MeasureSince([]string{\"nomad\", \"keyring\", \"rotate\"}, time.Now())\n\n\tif aclObj, err := k.srv.ResolveACL(args); err != nil {\n\t\treturn err\n\t} else if !aclObj.AllowOperatorOperation(acl.OperatorCapabilityKeyringRotate) {\n\t\treturn structs.ErrPermissionDenied\n\t}\n\n\tif args.Algorithm == \"\" {\n\t\targs.Algorithm = structs.EncryptionAlgorithmAES256GCM\n\t}\n\tif args.Full && args.PublishTime > 0 {\n\t\treturn fmt.Errorf(\"keyring cannot be prepublished and full rotated at the same time\")\n\t}\n\n\tunwrappedKey, err := structs.NewUnwrappedRootKey(args.Algorithm)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif args.PublishTime != 0 {\n\t\tunwrappedKey.Meta.State = structs.RootKeyStatePrepublished\n\t\tunwrappedKey.Meta.PublishTime = args.PublishTime\n\t} else {\n\t\tunwrappedKey.Meta.State = structs.RootKeyStateActive\n\t}\n\n\tisClusterUpgraded := k.srv.peersCache.ServersMeetMinimumVersion(\n\t\tk.srv.Region(), minVersionKeyringInRaft, true)\n\n\t// wrap/encrypt the key before we write it to Raft","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/keyring_endpoint.go#L38-L74","documentation":"The keyring rotate RPC creates a new root encryption key for vars/keyring operations. A rotation can either be a 'full' rotation (re-encrypt all existing data with the new key immediately) or a pre-publication (set a future PublishTime so the key becomes active later) — but not both, since a key that is already fully active cannot also be staged for future publication.","triggerScenarios":"Calling the keyring Rotate API / nomad keyring rotate with both -full and -publish-time (non-zero PublishTime) set. Raised at the start of Rotate before generating the new key.","commonSituations":"Operator runs 'nomad keyring rotate -full -publish-time=...' combining flags that are mutually exclusive; automation scripts merging rotation options; misunderstanding that pre-publishing implies eventual full rotation.","solutions":["Drop the -publish-time flag to perform an immediate full rotation","Drop the -full flag to stage the key with a publish time instead","Split operations: pre-publish now, then run a separate rotation when it should take effect"],"exampleFix":"// before\nnomad keyring rotate -full -publish-time=1735689600\n// after\nnomad keyring rotate -full\n// or\nnomad keyring rotate -publish-time=1735689600","handlingStrategy":"validation","validationCode":"// before calling rotate\nif full && publishTime != 0 {\n  return fmt.Errorf(\"-full and -publish-time are mutually exclusive\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Choose one rotation mode per invocation: immediate-full OR scheduled publish","Never merge flags from copied shell snippets blindly","Add CLI arg-validators in automation wrappers around keyring rotate"],"tags":["nomad","keyring","rotation","cli","mutually-exclusive-flags"],"backgroundTag":"mutually-exclusive-options","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}