ruvnet/ruflo · error

scanSecrets not available in JS fallback; use EnforcementGat

Error message

scanSecrets not available in JS fallback; use EnforcementGates

What it means

The JS fallback kernel returned by getKernel() throws from scanSecrets() because secret scanning in the fallback is delegated to the EnforcementGates class rather than reimplemented. The throw is a hard redirect: the operation exists, but only in the WASM kernel or via EnforcementGates. You only hit it when the WASM binary failed to load.

Source

Thrown at v3/@claude-flow/guidance/src/wasm-kernel.ts:176

  } else {
    // JS fallback — identical outputs, just slower
    kernelInstance = {
      available: false,
      version: 'js-fallback',

      sha256: jsSha256,
      hmacSha256: jsHmacSha256,
      contentHash: jsContentHash,
      signEnvelope: jsHmacSha256,
      verifyChain: () => {
        // Chain verification requires full envelope parsing — not implemented
        // in JS fallback because the ProofChain class already does it.
        throw new Error('verifyChain not available in JS fallback; use ProofChain.verifyChain()');
      },

      scanSecrets: (): string[] => {
        // Gate scanning in JS fallback defers to EnforcementGates class
        throw new Error('scanSecrets not available in JS fallback; use EnforcementGates');
      },
      detectDestructive: (): string | null => {
        throw new Error('detectDestructive not available in JS fallback; use EnforcementGates');
      },

      batchProcess: (): BatchResult[] => {
        throw new Error('batchProcess requires WASM kernel');
      },
    };
  }

  return kernelInstance;
}

/**
 * Check if the WASM kernel is available without initializing it.
 */
export function isWasmAvailable(): boolean {

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Use the EnforcementGates class for secret scanning — it is the supported pure-JS implementation
  2. Check isWasmAvailable() before choosing the kernel path, and branch accordingly
  3. Restore WASM loading (ship the .wasm asset, allow WebAssembly in runtime/CSP) if you need the fast path

Example fix

// before
const hits = getKernel().scanSecrets(content); // throws in JS fallback

// after
const hits = isWasmAvailable()
  ? getKernel().scanSecrets(content)
  : enforcementGates.scanSecrets(content); // JS implementation
Defensive patterns

Strategy: type-guard

Validate before calling

import { getKernel, isWasmAvailable } from './wasm-kernel.js';

function scanSecretsAnywhere(content: string, gates: EnforcementGates): string[] {
  return isWasmAvailable()
    ? getKernel().scanSecrets(content)
    : gates.scanSecrets(content); // supported JS implementation
}

Type guard

function supportsKernelScan(k: WasmKernel): boolean {
  return k.available; // false => fallback kernel: scanSecrets always throws
}

Try / catch

try {
  hits = kernel.scanSecrets(content);
} catch (e) {
  if (e instanceof Error && e.message.includes('JS fallback')) {
    hits = gates.scanSecrets(content);
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Calling getKernel().scanSecrets(content) when the WASM module did not load (missing .wasm asset, unsupported runtime, CSP restrictions) — the fallback kernel's scanSecrets stub throws immediately.

Common situations: Deploying to runtimes without WebAssembly; bundler configs that drop the wasm sidecar; security tools that gate WASM instantiation; tests that assume the accelerated kernel is always present.

Related errors


AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18). Data as JSON: /api/errors/9b025792ed19fb34. Report an issue: GitHub.