Skip to content

fix: Promise.any in validator script check is timing-dependent (Windows CI flake) #1007

@Wirasm

Description

@Wirasm

Bug

validateWorkflowResources in packages/workflows/src/validator.ts:417 uses Promise.any to check if a named script file exists:

const scriptExists = await Promise.any(
  extensions.map(ext => fileExists(join(scriptsDir, `${script}${ext}`)))
).catch(() => false);

fileExists always fulfills (returns true or false) — it never rejects. Promise.any resolves with the first fulfilled promise regardless of value. If the .js check resolves before .ts with false, Promise.any returns false even though the .ts file exists.

On Linux/macOS the .ts check wins the race consistently, but on Windows the ordering flips, causing the test to fail:

(fail) validateWorkflowResources — script nodes > no error when named bun script file exists
Expected length: 0
Received length: 1

CI run: https://github.com/coleam00/Archon/actions/runs/24195161565/job/70622954859

Fix

Change the promises to reject on non-existence so Promise.any filters correctly:

const scriptExists = await Promise.any(
  extensions.map(async ext => {
    const exists = await fileExists(join(scriptsDir, `${script}${ext}`));
    if (!exists) throw new Error('not found');
    return true;
  })
).catch(() => false);

Or use Promise.all + .some():

const results = await Promise.all(
  extensions.map(ext => fileExists(join(scriptsDir, `${script}${ext}`)))
);
const scriptExists = results.some(Boolean);

Location

  • packages/workflows/src/validator.ts:417-419
  • Test: packages/workflows/src/validator.test.ts:320-330

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions