apify/crawlee · error · Error

Duplicate load signal name ${JSON.stringify(name)}: ${hint}

Error message

Duplicate load signal name ${JSON.stringify(name)}: ${hint}

What it means

SystemStatus registers load signals by name and enforces uniqueness in its constructor. Passing two signals with the same name — or one shadowing a built-in signal's name — is ambiguous, so it throws with a hint explaining whether the clash is with a built-in or another custom signal.

Source

Thrown at packages/core/src/autoscaling/system_status.ts:176

    /**
     * Signal names are the keys of the reported {@apilink SystemInfo}, so a duplicate would leave a status object that
     * contradicts actual behavior: both signals are still evaluated (any overloaded one holds concurrency down), but
     * only the last is reported.
     */
    private assertUniqueSignalNames(): void {
        const seen = new Set<string>();

        for (const { name } of this.#signals) {
            if (!seen.has(name)) {
                seen.add(name);
                continue;
            }

            const hint = BUILTIN_SIGNAL_NAMES.has(name)
                ? `it is the name of a built-in signal. To replace that signal, switch it off with \`loadSignals: { ${BUILTIN_SIGNAL_OPTION_KEYS[name]}: false }\` and keep your implementation in \`loadSignals.custom\`; to run yours alongside it, give it a different name.`
                : 'two custom signals cannot share a name - rename one of them.';

            throw new Error(`Duplicate load signal name ${JSON.stringify(name)}: ${hint}`);
        }
    }

    /**
     * Returns an {@apilink SystemInfo} object with the following structure:
     *
     * ```javascript
     * {
     *     isSystemIdle: Boolean,
     *     memInfo: Object,
     *     eventLoopInfo: Object,
     *     cpuInfo: Object
     * }
     * ```
     *
     * Where the `isSystemIdle` property is set to `false` if the system
     * has been overloaded in the last `options.currentHistorySecs` seconds,
     * and `true` otherwise.

View on GitHub (pinned to dbe57fb09c)

Solutions

  1. Rename one of the duplicate custom signals.
  2. If the intent is to replace a built-in, disable it: `loadSignals: { <BUILTIN_KEY>: false }` and keep the implementation in `loadSignals.custom`.
  3. Deduplicate the array of signals before constructing SystemStatus.

Example fix

// before
new SystemStatus({ loadSignals: { custom: [{ name: 'cpu', ... }, { name: 'cpu', ... }] } });
// after
new SystemStatus({ loadSignals: { custom: [{ name: 'cpu', ... }, { name: 'gpu', ... }] } });
Defensive patterns

Strategy: validation

Validate before calling

const names = customSignals.map((s) => s.name);
const dupes = names.filter((n, i) => names.indexOf(n) !== i);
if (dupes.length) throw new Error(`Duplicate signal names: ${dupes.join(', ')}`);

Try / catch

try { const status = new SystemStatus({ loadSignals: { custom: signals } }); } catch (err) { if (err.message.includes('Duplicate load signal name')) { console.error(err.message); /* follow the hint: rename or disable the built-in */ } else { throw err; } }

Prevention

When it happens

Trigger: Passing two custom load signals with an identical `name` in `loadSignals.custom`; passing a custom signal whose name equals a built-in signal name (instead of disabling the built-in via `loadSignals: { <builtin>: false }`).

Common situations: Spreading an array of custom signals that contains duplicates; copying an example custom signal that reuses a built-in name; refactors merging two signal factories with the same default name.

Related errors


AI-assisted analysis of apify/crawlee@dbe57fb09c (2026-08-30). Data as JSON: /api/errors/c4bc526363b1a4a0. Report an issue: GitHub.