{"record":{"id":"a459f5b2e00a9c44","repo":"getsops/sops","slug":"error-loading-config-more-than-one-destinations-w","errorCode":null,"errorMessage":"error loading config: more than one destinations were found in a single destination rule, you can only use one per rule","messagePattern":"error loading config: more than one destinations were found in a single destination rule, you can only use one per rule","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"config/config.go","lineNumber":548,"sourceCode":"\n\tif dRule == nil {\n\t\treturn nil, fmt.Errorf(\"error loading config: no matching destination found in config\")\n\t}\n\n\tvar dest publish.Destination\n\tdestinationCount := 0\n\tif dRule.S3Bucket != \"\" {\n\t\tdestinationCount++\n\t}\n\tif dRule.GCSBucket != \"\" {\n\t\tdestinationCount++\n\t}\n\tif dRule.VaultPath != \"\" {\n\t\tdestinationCount++\n\t}\n\n\tif destinationCount > 1 {\n\t\treturn nil, fmt.Errorf(\"error loading config: more than one destinations were found in a single destination rule, you can only use one per rule\")\n\t}\n\tif dRule.S3Bucket != \"\" {\n\t\tdest = publish.NewS3Destination(dRule.S3Bucket, dRule.S3Prefix)\n\t}\n\tif dRule.GCSBucket != \"\" {\n\t\tdest = publish.NewGCSDestination(dRule.GCSBucket, dRule.GCSPrefix)\n\t}\n\tif dRule.VaultPath != \"\" {\n\t\tdest = publish.NewVaultDestination(dRule.VaultAddress, dRule.VaultPath, dRule.VaultKVMountName, dRule.VaultKVVersion)\n\t}\n\n\tconfig, err := configFromRule(rule, kmsEncryptionContext)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tconfig.Destination = dest\n\tconfig.OmitExtensions = dRule.OmitExtensions\n","sourceCodeStart":530,"sourceCodeEnd":566,"githubUrl":"https://github.com/getsops/sops/blob/13442bb98183887d7a9ac09ec8ab0564673a59d8/config/config.go#L530-L566","documentation":"A single destination rule may specify at most one publish destination. The destinationCount check increments for each of S3, GCS, Vault (and others) that are non-empty, and errors when more than one destination is set in the same rule, since sops can only upload to one destination per rule.","triggerScenarios":"One destination_rules entry sets two or more destination keys, e.g. both s3_bucket and gcs_bucket on the same rule.","commonSituations":"Merging destination rules for multi-cloud setups into a single entry; adding a new destination key to an existing rule instead of creating a second rule.","solutions":["Split the rule into multiple destination_rules entries, each with exactly one destination and its own path_regex","Remove the extra destination key from the rule, keeping only the intended one","If both destinations are genuinely needed, run sops twice with different configs or publish manually afterwards"],"exampleFix":"# before\n- path_regex: '.*'\n  s3_bucket: 'bkt'\n  gcs_bucket: 'gsbkt'\n# after\n- path_regex: '.*\\.s3\\.'\n  s3_bucket: 'bkt'\n- path_regex: '.*\\.gcs\\.'\n  gcs_bucket: 'gsbkt'","handlingStrategy":"validation","validationCode":"destKeys := []string{\"s3_bucket\",\"gcs_bucket\",\"vault_path\"}\ncount := 0\nfor _, k := range destKeys {\n    if v, _ := rule[k].(string); v != \"\" { count++ }\n}\nif count > 1 {\n    return errors.New(\"destination rule sets multiple destinations\")\n}","typeGuard":null,"tryCatchPattern":"cfg, err := configFromRule(rule, ctx)\nif err != nil && strings.Contains(err.Error(), \"more than one destinations\") {\n    return fmt.Errorf(\"split the destination rule into one rule per destination: %w\", err)\n}","preventionTips":["One destination key per destination rule — split multi-cloud rules into separate entries","Add a config schema that enforces at most one destination key per rule","Review destination_rules in PRs whenever adding S3/GCS/Vault keys"],"tags":["config","destination-rules","validation","sops"],"backgroundTag":"mutually-exclusive-config-options","analyzedSha":"13442bb98183887d7a9ac09ec8ab0564673a59d8","analyzedAt":"2026-09-01T03:53:00.447Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}