expo/expo · critical

Dylib not found at ${binaryPath}. Build it first by running:

Error message

Dylib not found at ${binaryPath}. Build it first by running: cd ${path.dirname(path.join(frameworkPath, '..'))} && ./scripts/build.sh

What it means

Thrown by getDylibPath() when the compiled IOSScreenInspectorFramework binary is not present at the expected path inside the e2e/image-comparison/inspector/bin directory. This framework is an out-of-tree native dylib that the iOS simulator screen inspector injects into the app via DYLD_INSERT_LIBRARIES. The error is a hard precondition gate: nothing in ScreenInspectorIOS can work until the binary is built.

Source

Thrown at apps/bare-expo/e2e/image-comparison/inspector/ScreenInspectorIOS.ts:47

  bounds?: {
    x: number;
    y: number;
    width: number;
    height: number;
  };
  path?: string;
  width?: number;
  height?: number;
  error: string;
}

export function getDylibPath(): string {
  const frameworkName = 'IOSScreenInspectorFramework.framework';
  const frameworkPath = path.resolve(__dirname, 'bin', frameworkName);
  const binaryPath = path.join(frameworkPath, 'IOSScreenInspectorFramework');

  if (!fs.existsSync(binaryPath)) {
    throw new Error(
      `Dylib not found at ${binaryPath}. Build it first by running: cd ${path.dirname(path.join(frameworkPath, '..'))} && ./scripts/build.sh`
    );
  }

  return binaryPath;
}

export class ScreenInspectorIOS {
  private requestPipePath = '/tmp/ios_screen_inspector_request';
  private responsePipePath = '/tmp/ios_screen_inspector_response';

  async getCoordinates(
    accessibilityId: string,
    timeoutMs: number = 15000
  ): Promise<{
    x: number;
    y: number;
    width: number;

View on GitHub (pinned to b09195aac2)

Solutions

  1. Run the exact build command the message prints: cd into path.dirname of the parent of bin (the inspector package root) and execute ./scripts/build.sh to compile the framework.
  2. Confirm the binary now exists at the path printed in the error (the IOSScreenInspectorFramework executable inside bin/IOSScreenInspectorFramework.framework), not just the .framework directory.
  3. If build.sh fails, run it directly and read its output — it typically requires Xcode command line tools and a valid iOS SDK; ensure xcode-select points at the active developer dir.
  4. On non-macOS hosts, these tests are unsupported — gate them behind a darwin platform check rather than letting getDylibPath throw.

Example fix

// before: tests run on any platform and throw at getDylibPath()
if (process.platform !== 'darwin') {
  throw new Error('iOS screen inspector e2e requires macOS');
}
// after: ensure the framework is built before constructing the inspector
import { execSync } from 'child_process';
import { existsSync } from 'fs';
import path from 'path';

const frameworkBinary = path.resolve(__dirname, 'bin', 'IOSScreenInspectorFramework.framework', 'IOSScreenInspectorFramework');
if (!existsSync(frameworkBinary)) {
  execSync('./scripts/build.sh', { stdio: 'inherit', cwd: path.resolve(__dirname, '..') });
}
Defensive patterns

Strategy: validation

Validate before calling

import { existsSync } from 'fs';
import path from 'path';

const frameworkBinary = path.resolve(__dirname, 'bin', 'IOSScreenInspectorFramework.framework', 'IOSScreenInspectorFramework');
const isDylibBuilt = existsSync(frameworkBinary);
if (!isDylibBuilt) {
  throw new Error(`Framework not built. Run ./scripts/build.sh in ${path.resolve(__dirname, '..')}`);
}

Prevention

When it happens

Trigger: Calling getDylibPath() (directly, or transitively through ScreenInspectorIOS.getCoordinates / captureView / startSimulatorAppWithDylib) on a fresh checkout, after a clean, after switching branches that touch the framework, or on a CI runner where the build step was skipped or failed. The check is fs.existsSync(binaryPath) failing on the framework's executable file (not the .framework bundle).

Common situations: Running e2e image-comparison tests for the first time without running the build script; the framework was .gitignored so a clone lacks it; a previous ./scripts/build.sh failed silently; running on a non-macOS host where the framework cannot be compiled at all.

Related errors


AI-assisted analysis of expo/expo@b09195aac2 (2026-08-12). Data as JSON: /api/errors/6e0afcbfcd66c898. Report an issue: GitHub.