can1357/oh-my-pi · error · Error

Invalid global daemon service name: ${JSON.stringify(service

Error message

Invalid global daemon service name: ${JSON.stringify(service)}

What it means

getGlobalDaemonRuntimeDir(service) builds a machine-global runtime directory path by joining the service name under the daemon runtime root. Because the name becomes a filesystem path segment, it is validated against /^[a-z0-9][a-z0-9._-]*$/i; any name containing path separators, leading dots, spaces, or other special characters throws this error to prevent path traversal or malformed runtime paths.

Source

Thrown at packages/utils/src/dirs.ts:971

export function getDaemonRuntimeRoot(): string {
	return dirs.rootSubdir(path.join("run", "daemons"), "state");
}

/** Get the daemon runtime directory for a project (~/.omp/run/daemons/<hash>; XDG default: $XDG_STATE_HOME/omp/run/daemons/<hash>). */
export function getDaemonRuntimeDir(projectDir: string): string {
	const key = Bun.hash.wyhash(path.resolve(projectDir)).toString(16).padStart(16, "0");
	return path.join(getDaemonRuntimeRoot(), key);
}

/** Root directory containing every machine-global daemon service scope. */
export function getGlobalDaemonRuntimeRoot(): string {
	return path.join(getBaseConfigRoot(), "run", "daemons", "global");
}

/** Get a profile-independent runtime directory for a machine-global daemon service. */
export function getGlobalDaemonRuntimeDir(service: string): string {
	if (!/^[a-z0-9][a-z0-9._-]*$/i.test(service)) {
		throw new Error(`Invalid global daemon service name: ${JSON.stringify(service)}`);
	}
	return path.join(getGlobalDaemonRuntimeRoot(), service);
}

/** Get the provider in-flight root directory (~/.omp/run/provider-inflight; XDG default: $XDG_STATE_HOME/omp/run/provider-inflight). */
export function getProviderInFlightRoot(): string {
	return dirs.rootSubdir(path.join("run", "provider-inflight"), "state");
}

/** Get the marketplaces registry path (~/.omp/marketplaces.json; XDG default: $XDG_DATA_HOME/omp/marketplaces.json). Adopts a legacy registry on first XDG resolution. */
export function getMarketplacesRegistryPath(): string {
	const registryPath = dirs.rootSubdir("marketplaces.json", "data");
	adoptLegacyFile(path.join(dirs.configRoot, "marketplaces.json"), registryPath);
	return registryPath;
}

// =============================================================================
// Project subdirectories (.omp/*)

View on GitHub (pinned to 9690622007)

Solutions

  1. Sanitize the service name before calling: strip or replace illegal characters, e.g. name.replace(/[^a-zA-Z0-9._-]/g, "-").
  2. Ensure the name starts with an alphanumeric character (prepend one or trim leading dots/dashes).
  3. Derive the service name from a fixed, known identifier (package/tool name) rather than free-form user input.
  4. Validate with the same regex the library uses ( /^[a-z0-9][a-z0-9._-]*$/i ) at your config-loading boundary and reject invalid config early.

Example fix

// before
const dir = getGlobalDaemonRuntimeDir(`${org}/${tool}`); // "acme/preview" throws

// after
const service = `${org}-${tool}`.replace(/[^a-zA-Z0-9._-]/g, "-").replace(/^[^a-zA-Z0-9]+/, "");
const dir = getGlobalDaemonRuntimeDir(service);
Defensive patterns

Strategy: validation

Validate before calling

const SERVICE_RE = /^[a-z0-9][a-z0-9._-]*$/i;
function isValidDaemonService(name: string): boolean {
  return SERVICE_RE.test(name);
}
if (!isValidDaemonService(service)) throw new Error(`Refusing invalid daemon service name: ${service}`);

Type guard

function isValidDaemonService(name: string): boolean {
  return /^[a-z0-9][a-z0-9._-]*$/i.test(name);
}

Try / catch

let dir: string;
try {
  dir = getGlobalDaemonRuntimeDir(service);
} catch (err) {
  if (err instanceof Error && err.message.startsWith("Invalid global daemon service name")) {
    dir = getGlobalDaemonRuntimeDir(sanitizeServiceName(service));
  } else throw err;
}

Prevention

When it happens

Trigger: Calling getGlobalDaemonRuntimeDir() with a service string that is empty, starts with a dot or non-alphanumeric character, or contains characters outside [a-z0-9._-] — e.g. "my daemon", "svc/v2", "../escape", "-svc", "".

Common situations: Passing a user-supplied profile/project name straight through as the daemon service name; building the service id by concatenating strings with slashes or colons (e.g. "org:tool"); interpolating an env value or config key that contains spaces or dots at the start.

Related errors


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