ruvnet/ruflo · error
Event log path contains null bytes
Error message
Event log path contains null bytes
What it means
validatePath() rejects any event-log path containing a NUL byte before it reaches Node's fs APIs. Paths with embedded NULs are invalid on Linux/macOS (ERR_INVALID_ARG_VALUE) and are also a classic path-injection vector, so RvfEventLog construction/initialization fails fast with this message. The offending value almost always originates from user input, config files, or environment variables.
Source
Thrown at v3/@claude-flow/shared/src/events/rvf-event-log.ts:28
* Record: 4 bytes (uint32 BE payload length) + N bytes (JSON payload)
*
* In-memory indexes are rebuilt on initialize() by replaying the file.
* Snapshots are stored in a separate `.snap.rvf` file using the same format.
*
* @module v3/shared/events/rvf-event-log
*/
import { EventEmitter } from 'node:events';
import { existsSync, mkdirSync, readFileSync, writeFileSync, appendFileSync, renameSync } from 'node:fs';
import { dirname } from 'node:path';
import type { DomainEvent } from './domain-events.js';
// Re-export shared interfaces so consumers do not need to import event-store.ts
import type { EventFilter, EventSnapshot, EventStoreStats } from './event-store.js';
/** Validate a file path is safe */
function validatePath(p: string): void {
if (p.includes('\0')) throw new Error('Event log path contains null bytes');
}
// =============================================================================
// Configuration
// =============================================================================
export interface RvfEventLogConfig {
/** Path to event log file */
logPath: string;
/** Enable verbose logging */
verbose?: boolean;
/** Maximum events before snapshot recommendation */
snapshotThreshold?: number;
}
const DEFAULT_CONFIG: Required<RvfEventLogConfig> = {
logPath: 'events.rvf',
verbose: false,View on GitHub (pinned to fa13ee4ad6)
Solutions
- Strip NULs at the source: logPath.replace(/\0/g, '') — but prefer fixing the upstream producer
- Decode buffers on their exact byte range (buf.toString('utf8', start, end)) instead of converting NUL-padded buffers wholesale
- Validate externally supplied paths with the same includes('\0') check before constructing RvfEventLog
Example fix
// before
const logPath = buf.toString(); // may contain NUL padding
const log = new RvfEventLog({ logPath }); // throws
// after
const logPath = buf.subarray(0, buf.indexOf(0)).toString('utf8');
const log = new RvfEventLog({ logPath }); Defensive patterns
Strategy: validation
Validate before calling
function safeLogPath(p: string): string {
if (p.includes('\0')) throw new Error('log path contains NUL bytes');
return p;
}
const log = new RvfEventLog({ logPath: safeLogPath(fromEnv) }); Type guard
function isValidPath(p: unknown): p is string {
return typeof p === 'string' && p.length > 0 && !p.includes('\0');
} Prevention
- Never build paths from raw buffers; decode the exact byte range up to the first NUL
- Validate external path input (env vars, CLI args, config) for NUL bytes before use
- Watch for invisible control characters when copy-pasting config values
When it happens
Trigger: Passing a logPath built from env vars or CLI input containing a NUL byte; strings decoded from fixed-length buffers padded with NULs and not trimmed; template concatenation that pulls binary data into a path.
Common situations: Reading paths from IPC messages or C-style buffers sliced mid-string; config values pasted with invisible control characters; mis-decoded multibyte input producing NUL padding.
Related errors
- unknown game "${key}". Known: ${Object.keys(GAMES).join(', '
- ${label} contains null bytes
- ${label} contains shell metacharacters
- AI job registry is a symlink (refusing): ${path}
- AI budget file is a symlink (refusing): ${path}
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/262e294947d1c454.
Report an issue: GitHub.