Yeachan-Heo/oh-my-codex · error · Error

failed to run notify-hook: ${result.error.message}

Error message

failed to run notify-hook: ${result.error.message}

What it means

During `omx tmux-hook test`, the CLI spawns notify-hook.js with `node <hook> <json-payload>` via spawnSync. This error is the spawn-level failure (result.error), meaning Node could not launch the process at all — typically the executable path is wrong, permissions are denied, or resources are exhausted. It is distinct from error 483, which covers a launched hook that exited non-zero.

Source

Thrown at src/cli/tmux-hook.ts:474

  const threadId = `tmux-test-${Date.now()}`;
  const turnId = `turn-${Date.now()}`;
  const message = args.join(' ').trim() || 'tmux-hook test payload';
  const payload = {
    type: 'agent-turn-complete',
    cwd,
    'thread-id': threadId,
    'turn-id': turnId,
    'input-messages': ['omx tmux-hook test'],
    'last-assistant-message': message,
  };

  const result = spawnSync(process.execPath, [notifyHook, JSON.stringify(payload)], {
    cwd,
    encoding: 'utf-8',
      windowsHide: true,
    });
  if (result.error) {
    throw new Error(`failed to run notify-hook: ${result.error.message}`);
  }
  if (result.status !== 0) {
    throw new Error(`notify-hook exited ${result.status}: ${(result.stderr || result.stdout || '').trim()}`);
  }

  console.log('tmux-hook test: notify-hook executed.');
  console.log(`thread_id=${threadId}`);
  console.log(`turn_id=${turnId}`);
  console.log('Check: .omx/logs/tmux-hook-YYYY-MM-DD.jsonl for skip/reason codes.');
}

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Confirm the file still exists at the printed path and re-run build if not (`npm run build`)
  2. Fix permissions: `chmod +x dist/scripts/notify-hook.js` (and ensure read access)
  3. Check for concurrent processes (file watchers, reinstall jobs) deleting dist/ during the test
  4. On EMFILE/ENOMEM, free file descriptors/memory or raise ulimit and retry

Example fix

// before
omx tmux-hook test hello
// Error: failed to run notify-hook: spawn ENOENT

// after
ls dist/scripts/notify-hook.js || npm run build
chmod +x dist/scripts/notify-hook.js
omx tmux-hook test hello
Defensive patterns

Strategy: fallback

Validate before calling

import { existsSync, accessSync, constants } from 'node:fs';
function canRunHook(hook: string): boolean {
  try { accessSync(hook, constants.R_OK); return existsSync(hook); } catch { return false; }
}

Try / catch

try { await testTmuxHook(args); } catch (e) { if (e instanceof Error && e.message.startsWith('failed to run notify-hook')) { await rebuildPackage(); await testTmuxHook(args); } else throw e; }

Prevention

When it happens

Trigger: spawnSync(process.execPath, [notifyHook, payload]) returns an error object: ENOENT if notifyHook path vanished between the existsSync check and spawn, EACCES if the file lost execute/read permission, or EMFILE/ENOMEM under resource pressure.

Common situations: File deleted or moved concurrently (watcher/reinstall mid-test); permission bits stripped by a copy/docker step; CI runners with low file-descriptor limits; antivirus quarantine on Windows.

Related errors


AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27). Data as JSON: /api/errors/063d9eb4d3777763. Report an issue: GitHub.