JuliusBrussee/caveman · error

caveman agent: invalid agent id

Error message

caveman agent: invalid agent id ${JSON.stringify(options.id)}

What it means

The agent() definition factory validates the agent id against /^[a-z0-9][a-z0-9_-]{0,95}$/ and throws with a JSON-stringified copy of the invalid id. Ids must start with a lowercase letter or digit, contain only lowercase alphanumerics, underscores, and hyphens, and be at most 96 characters.

Solutions

  1. Slugify the id: lowercase, replace invalid characters with '-' or '_'
  2. Strip leading characters that are not [a-z0-9] and truncate to 96 chars
  3. Validate the id with the same regex in your own code before calling agent()
  4. Use a stable kebab-case identifier instead of a display name

Example fix

// before
agent({ id: "My Research Agent", ... });
// after
const id = "My Research Agent".toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+/, "").slice(0, 96);
agent({ id, ... });
Defensive patterns

Strategy: validation

Validate before calling

const AGENT_ID_RE = /^[a-z0-9][a-z0-9_-]{0,95}$/;
if (!AGENT_ID_RE.test(id)) throw new Error(`invalid agent id: ${id}`);

Type guard

const isValidAgentId = (id) => typeof id === "string" && /^[a-z0-9][a-z0-9_-]{0,95}$/.test(id);

Try / catch

try { def = agent({ id, ...rest }); } catch (err) { if (String(err.message).startsWith("caveman agent: invalid agent id")) { def = agent({ id: slugify(id), ...rest }); } else throw err; }

Prevention

When it happens

Trigger: agent({ id: 'My Agent' }) (uppercase/space); empty string; id starting with '-' or '_'; ids longer than 96 chars; ids with dots or unicode characters.

Common situations: Deriving ids from human-readable project names with spaces/camelCase; using UUIDs with uppercase; templating ids from environment names like 'Prod.EU'.

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 JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/3903753d33d38d96. Report an issue: GitHub.

Appendix: source

Thrown at packages/agent/src/index.ts:99

const SANDBOX_MODES: readonly AgentDefinition["sandbox"][] = [
  "required",
  "fixture",
  "host",
];

export function agent(options: {
  id: string;
  instructions: string | FileSource;
  model: Auto | string | Model<Api>;
  reasoning?: AgentDefinition["reasoning"];
  tools?: ToolDefinition[];
  contexts?: ContextDefinition[];
  memory?: MemoryDefinition;
  output?: OutputDefinition;
  sandbox?: AgentDefinition["sandbox"];
}): AgentDefinition {
  if (!/^[a-z0-9][a-z0-9_-]{0,95}$/.test(options.id)) {
    throw new Error(`caveman agent: invalid agent id ${JSON.stringify(options.id)}`);
  }
  const tools = Object.freeze([...(options.tools ?? [])]);
  if (new Set(tools.map((item) => item.name)).size !== tools.length) {
    throw new Error("caveman agent: duplicate tool name");
  }
  const sandbox = options.sandbox ?? "required";
  if (!SANDBOX_MODES.includes(sandbox)) {
    throw new Error(`caveman agent: unknown sandbox mode ${JSON.stringify(sandbox)}`);
  }
  const reserved = tools.find((item) => item.name.startsWith("cave_"));
  if (reserved) {
    throw new Error(
      `caveman agent: tool prefix cave_ is reserved by framework (${reserved.name})`,
    );
  }
  const definition: AgentDefinition = {
    kind: "agent",
    id: options.id,

View on GitHub (pinned to 3ee70a1026)