gchq/CyberChef · error · OperationError

${name} connects ${pair[0]} more than once

Error message

${name} connects ${pair[0]} more than once

What it means

Thrown by the PairMapBase constructor when a letter appears in more than one pair — the map already has an entry for that letter. Each letter may be connected to at most one partner (self-stecker pairs like 'AA' are silently ignored). The error interpolates name (e.g. 'Plugboard' or 'Reflector') and the offending letter.

Source

Thrown at src/core/lib/Enigma.mjs:188

    constructor(pairs, name="PairMapBase") {
        // I've chosen to make whitespace significant here to make a) code and
        // b) inputs easier to read
        this.pairs = pairs;
        this.map = {};
        if (pairs === "") {
            return;
        }
        pairs.split(/\s+/).forEach(pair => {
            if (!/^[A-Z]{2}$/.test(pair)) {
                throw new OperationError(name + " must be a whitespace-separated list of uppercase letter pairs");
            }
            const a = a2i(pair[0]), b = a2i(pair[1]);
            if (a === b) {
                // self-stecker
                return;
            }
            if (Object.prototype.hasOwnProperty.call(this.map, a)) {
                throw new OperationError(`${name} connects ${pair[0]} more than once`);
            }
            if (Object.prototype.hasOwnProperty.call(this.map, b)) {
                throw new OperationError(`${name} connects ${pair[1]} more than once`);
            }
            this.map[a] = b;
            this.map[b] = a;
        });
    }

    /**
     * Transform a character through this object.
     * Returns other characters unchanged.
     *
     * @param {number} c - The character.
     * @returns {number}
     */
    transform(c) {
        if (!Object.prototype.hasOwnProperty.call(this.map, c)) {

View on GitHub (pinned to 4290ea7539)

Solutions

  1. Ensure each letter appears in at most one pair across the whole spec.
  2. Before constructing, build a usage map and reject any letter seen twice.
  3. Deduplicate pairs and remove conflicting entries.

Example fix

// before
new Plugboard('AY AB CD'); // A connected to Y and B

// after
new Plugboard('AY BC DE'); // each letter unique
Defensive patterns

Strategy: validation

Validate before calling

function hasNoDoubleConnect(pairs) {
  const seen = new Set();
  for (const tok of pairs.split(/\s+/).filter(Boolean)) {
    const [a, b] = [tok[0], tok[1]];
    if (a === b) continue; // self-stecker allowed
    if (seen.has(a) || seen.has(b)) return false;
    seen.add(a); seen.add(b);
  }
  return true;
}
if (!hasNoDoubleConnect(pairs)) {
  throw new Error("Each letter may appear in at most one pair.");
}

Type guard

function isNonOverlappingPairs(pairs) {
  const seen = new Set();
  for (const tok of pairs.split(/\s+/).filter(Boolean)) {
    const [a, b] = [tok[0], tok[1]];
    if (a === b) continue;
    if (seen.has(a) || seen.has(b)) return false;
    seen.add(a); seen.add(b);
  }
  return true;
}

Prevention

When it happens

Trigger: new Plugboard('AY AB ...') or new Reflector(...) where 'A' is connected to both Y and B — the second pair triggers hasOwnProperty(map, a) and throws. Same for the partner letter (the b-side check covers reversed overlaps).

Common situations: Listing a plugboard connection twice for the same letter; copying a reflector spec that double-binds a letter; editing a pair and forgetting to remove the old one; overlapping pairs from merge errors.

Related errors


AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13). Data as JSON: /api/errors/fdbc678556daa81b. Report an issue: GitHub.