can1357/oh-my-pi · error

Daemon name must be 1-48 letters, numbers, dots, underscores

Error message

Daemon name must be 1-48 letters, numbers, dots, underscores, or hyphens

What it means

DaemonBroker.#start validates the daemon name against /^[A-Za-z0-9][A-Za-z0-9._-]{0,47}$/ before creating anything: the name must be 1-48 chars, start with a letter or digit, and use only letters, digits, dots, underscores, hyphens. This guards downstream use of the name in process management, file paths, and subscription keys from path/lookup injection or collisions.

Source

Thrown at packages/coding-agent/src/launch/broker.ts:598

				const record = this.#record(operation.name);
				await this.#stopRecord(record, operation.timeoutMs);
				return { op: "stop", daemon: record.snapshot };
			}
			case "restart":
				return this.#restart(operation.name);
			case "describe": {
				const record = this.#record(operation.name);
				await this.#refreshDetached(record);
				return { op: "describe", daemon: record.snapshot, spec: record.spec };
			}
			case "shutdown":
				return { op: "shutdown" };
		}
	}

	async #start(spec: DaemonSpec, owner?: string): Promise<DaemonRpcResult> {
		if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,47}$/.test(spec.name)) {
			throw new Error("Daemon name must be 1-48 letters, numbers, dots, underscores, or hyphens");
		}
		if (spec.detached && spec.pty) {
			throw new Error("A detached daemon cannot allocate a PTY");
		}
		if (
			spec.pty &&
			process.platform === "win32" &&
			[".bat", ".cmd"].includes(path.extname(spec.application).toLowerCase())
		) {
			throw new Error('Windows batch files require application "cmd.exe" with the batch path after "/c"');
		}
		if (this.#startingNames.has(spec.name)) {
			throw new Error(`Daemon ${spec.name} is already starting`);
		}
		this.#startingNames.add(spec.name);
		let record: ManagedDaemon;
		try {
			const existing = this.#records.get(spec.name);

View on GitHub (pinned to 9690622007)

Solutions

  1. Rename the daemon to a 1-48 char string matching [A-Za-z0-9][A-Za-z0-9._-]* (must start with alphanumeric)
  2. Sanitize derived names: strip/replace invalid characters and truncate to 48 chars, prefixing with an alphanumeric if needed
  3. Validate the name client-side with the same regex before issuing the start request

Example fix

// before
await broker.start({ name: `daemon for ${projectPath}` }); // spaces and slashes -> throws
// after
const safe = projectPath.replace(/[^A-Za-z0-9._-]+/g, '-').replace(/^[._-]+/, '').slice(0, 48) || 'daemon';
await broker.start({ name: safe });
Defensive patterns

Strategy: validation

Validate before calling

const DAEMON_NAME_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,47}$/;
function isValidDaemonName(name: string): boolean { return DAEMON_NAME_RE.test(name); }
if (!isValidDaemonName(spec.name)) throw new Error(`Invalid daemon name: ${spec.name}`);

Try / catch

try {
  await broker.start(spec);
} catch (err) {
  if (err instanceof Error && err.message.startsWith('Daemon name must be')) {
    return broker.start({ ...spec, name: sanitizeDaemonName(spec.name) });
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling the broker's start/startDaemon RPC (via #start) with a name that is empty, longer than 48 chars, starts with '.', '_' or '-', or contains characters like spaces, slashes, '@', or unicode.

Common situations: Deriving daemon names from user input, project paths, or branch names that contain slashes or spaces; generating names via templating that yields empty strings; suffixing IDs to names and exceeding the 48-char limit; localized/unicode names from non-ASCII project titles.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/2b61b9fce402f46c. Report an issue: GitHub.