can1357/oh-my-pi · error · Error
experiment id must be a non-empty token of [A-Za-z0-9_.] (ru
Error message
experiment id must be a non-empty token of [A-Za-z0-9_.] (runs group as `<id>-<arm>`)
What it means
createExperiment validates the experiment id against `/^[A-Za-z0-9_.]+$/` and throws this error for anything else (empty, whitespace-only, or containing dashes/spaces/slashes). Dashes are structurally forbidden because `experimentOf` groups job names by the token before the first dash — a dashed id could never own its runs. The id must be a non-empty token of letters, digits, underscore, and dot.
Source
Thrown at packages/metaharness/src/server.ts:527
this.#tick();
});
this.#store.registerLaunch({ ...record, pid: proc.pid });
this.#tick();
return proc.pid;
}
/** Liveness check that survives manager restarts: managed child, or a running row with a live pid. */
#runLive(run: RunRow): boolean {
return this.#children.has(run.jobName) || (run.status === "running" && pidAlive(run.pid));
}
/** Register an experiment id (with an optional goal) so it is browsable before its first arm. */
createExperiment(req: CreateExperimentRequest): { id: string; goal: string } {
const id = req.id?.trim() ?? "";
// Dashes are structurally impossible: `experimentOf` groups job names by
// the token before the first dash, so a dashed id could never own a run.
if (!/^[A-Za-z0-9_.]+$/.test(id)) {
throw new Error("experiment id must be a non-empty token of [A-Za-z0-9_.] (runs group as `<id>-<arm>`)");
}
const goal = req.goal ?? this.#store.getExperimentMeta(id)?.goal ?? "";
this.#store.setExperimentGoal(id, goal);
return { id, goal };
}
/** Apply goal + per-run role/note metadata; used by the UI and for backfill. */
updateExperimentMeta(id: string, update: ExperimentMetaUpdate): { id: string; updatedRuns: string[] } {
if (update.goal !== undefined) this.#store.setExperimentGoal(id, update.goal);
const updatedRuns: string[] = [];
for (const jobName in update.runs) {
if (experimentOf(jobName) !== id) continue;
if (this.#store.setRunMeta(jobName, update.runs[jobName])) updatedRuns.push(jobName);
}
this.#tick();
return { id, updatedRuns };
}
View on GitHub (pinned to 9690622007)
Solutions
- Sanitize the id: replace disallowed characters with `_` or `.` before calling createExperiment
- Remove dashes (e.g. `my-exp` → `my_exp` or `myexp`) since dashes are the run-name grouping separator
- Ensure the id is non-empty after trimming
- Validate with the same regex client-side: /^[A-Za-z0-9_.]+$/
Example fix
// before
server.createExperiment({ id: "feat/new-agent" }); // throws
// after
const raw = "feat/new-agent";
const id = raw.replace(/[^A-Za-z0-9_.]/g, "_"); // "feat_new_agent"
server.createExperiment({ id }); Defensive patterns
Strategy: validation
Validate before calling
const EXPERIMENT_ID_RE = /^[A-Za-z0-9_.]+$/;
function validExperimentId(id: string | undefined): boolean {
return typeof id === "string" && EXPERIMENT_ID_RE.test(id.trim());
} Type guard
function isValidExperimentId(id: unknown): id is string {
return typeof id === "string" && /^[A-Za-z0-9_.]+$/.test(id);
} Try / catch
try {
server.createExperiment({ id });
} catch (err) {
if (err instanceof Error && err.message.startsWith("experiment id must be")) {
throw new Error(`invalid experiment id "${id}": use [A-Za-z0-9_.], no dashes`);
}
throw err;
} Prevention
- Sanitize derived ids (branch names, slugs) with .replace(/[^A-Za-z0-9_.]/g, "_")
- Never use dashes — they are the arm-grouping separator
- Trim ids before sending
- Validate client-side with the same regex
When it happens
Trigger: Calling `createExperiment({ id })` with an empty/undefined id, an id containing `-`, spaces, `/`, or other punctuation, or an id with leading/trailing whitespace that trims to empty.
Common situations: Deriving the experiment id from a branch name or URL slug that contains dashes; passing a raw user string without sanitizing; forgetting to pass `id` at all.
Related errors
- Invalid skill name "${raw}". Use lowercase letters, digits,
- Unknown tool${unknown.length === 1 ? "" : "s"} in --tools: $
- Unknown OAuth provider '${providerArg}'. Known: ${providers
- Invalid marketplace plugin package name: ${JSON.stringify(na
- Invalid plugin name: "${name}"
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/133631ab29c3dae8.
Report an issue: GitHub.