conductor-oss/conductor · critical · IllegalStateException

conductor.file-storage.conductor.signing.keys contains dupli

Error message

conductor.file-storage.conductor.signing.keys contains duplicate id: {}

What it means

Thrown by SigningProperties.validate() when two or more key entries share the same id. Signing keys are keyed by id (the first signs new URLs; all verify), so duplicate ids are ambiguous and rejected at startup with an IllegalStateException naming the offending id.

Source

Thrown at core/src/main/java/org/conductoross/conductor/core/storage/ConductorFileStorageProperties.java:120

        }

        /** Throws a startup-friendly error for unusable key configuration. */
        public void validate() {
            if (!enabled) {
                return;
            }
            if (keys == null || keys.isEmpty()) {
                throw new IllegalStateException(
                        "conductor.file-storage.conductor.signing.keys is required when signing is enabled");
            }
            Set<String> ids = new HashSet<>();
            for (Key key : keys) {
                if (key == null || isBlank(key.getId()) || isBlank(key.getSecret())) {
                    throw new IllegalStateException(
                            "Each conductor.file-storage.conductor.signing.keys entry requires id and secret");
                }
                if (!ids.add(key.getId())) {
                    throw new IllegalStateException(
                            "conductor.file-storage.conductor.signing.keys contains duplicate id: "
                                    + key.getId());
                }
            }
        }

        private boolean isBlank(String value) {
            return value == null || value.isBlank();
        }
    }

    /** An ordered signing key. The first key signs new URLs; every key verifies existing URLs. */
    public static class Key {

        @NotBlank private String id;
        @NotBlank private String secret;

        public String getId() {

View on GitHub (pinned to cf7c3e4a8a)

Solutions

  1. Give each key entry a unique id (e.g. key-1, key-2).
  2. When rotating, keep the old key (same id is fine) only once and add a new key with a new id.
  3. Audit the resolved config for duplicates (print ids).

Example fix

# before - duplicate ids
signing:
  enabled: true
  keys:
    - id: key-1
      secret: ${OLD_SECRET}
    - id: key-1
      secret: ${NEW_SECRET}

# after - unique ids
signing:
  enabled: true
  keys:
    - id: key-1
      secret: ${OLD_SECRET}
    - id: key-2
      secret: ${NEW_SECRET}
Defensive patterns

Strategy: validation

Validate before calling

Set<String> ids = props.getSigning().getKeys().stream().map(Key::getId).collect(Collectors.toSet());
boolean unique = ids.size() == props.getSigning().getKeys().size();

Prevention

When it happens

Trigger: Two entries under conductor.file-storage.conductor.signing.keys with the same id value while signing is enabled.

Common situations: Rotating keys by copy-pasting an entry and forgetting to change the id; merging config from multiple sources that both define key-1; templating that duplicates a key block.

Related errors


AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14). Data as JSON: /api/errors/8b3e62a9cc8513da. Report an issue: GitHub.