paperclipai/paperclip · error · Error
Invalid --expires-at value: ${opts.expiresAt}
Error message
Invalid --expires-at value: ${opts.expiresAt} What it means
Thrown by resolveBoardKeyExpiresAt (token.ts:235) when --expires-at is provided but new Date(value).getTime() is not finite, i.e. the string cannot be parsed into a valid date. Pre-empts sending a bad expiresAt to /api/board-api-keys.
Source
Thrown at cli/src/commands/client/token.ts:235
async function resolveAgent(api: { get<T>(path: string): Promise<T | null> }, companyId: string, agentRef: string): Promise<Agent> {
const trimmed = agentRef.trim();
if (!trimmed) throw new Error("Agent reference is required");
if (/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(trimmed)) {
const agent = await api.get<Agent>(apiPath`/api/agents/${trimmed}`);
if (!agent || agent.companyId !== companyId) throw new Error(`Agent not found: ${agentRef}`);
return agent;
}
const query = new URLSearchParams({ companyId });
const agent = await api.get<Agent>(`${apiPath`/api/agents/${trimmed}`}?${query.toString()}`);
if (!agent || agent.companyId !== companyId) throw new Error(`Agent not found: ${agentRef}`);
return agent;
}
function resolveBoardKeyExpiresAt(opts: BoardTokenOptions): Date | null | undefined {
if (opts.neverExpires) return null;
if (opts.expiresAt?.trim()) {
const date = new Date(opts.expiresAt.trim());
if (!Number.isFinite(date.getTime())) throw new Error(`Invalid --expires-at value: ${opts.expiresAt}`);
return date;
}
if (opts.ttlDays?.trim()) {
const days = Number(opts.ttlDays);
if (!Number.isFinite(days) || days <= 0) throw new Error(`Invalid --ttl-days value: ${opts.ttlDays}`);
return new Date(Date.now() + Math.floor(days * 24 * 60 * 60 * 1000));
}
return undefined;
}
View on GitHub (pinned to 67001ec6eb)
Solutions
- Use an ISO 8601 timestamp: --expires-at 2025-12-31T23:59:59Z.
- Prefer --ttl-days for relative expiries.
- Validate the date string with `new Date(value)` in your shell before passing it.
Example fix
// before --expires-at "Dec 31" // after --expires-at "2025-12-31T00:00:00Z"
Defensive patterns
Strategy: validation
Validate before calling
function isValidExpiresAt(value: string | undefined): boolean {
if (!value?.trim()) return false;
return Number.isFinite(new Date(value.trim()).getTime());
}
if (opts.expiresAt && !isValidExpiresAt(opts.expiresAt)) {
console.error(`--expires-at "${opts.expiresAt}" is not a valid date. Use ISO 8601.`);
process.exit(1);
} Type guard
function isParsableDate(value: string): boolean {
return Number.isFinite(new Date(value).getTime());
} Prevention
- Use ISO 8601 timestamps with explicit timezone (trailing Z or offset).
- Prefer --ttl-days for relative expiries.
- Test the date string with `new Date(value)` in your shell first.
When it happens
Trigger: Passing --expires-at "next week", --expires-at "2025-13-40", or any non-ISO/non-RFC2822 string. The Date constructor returns Invalid Date and getTime() yields NaN.
Common situations: Locale-specific date formats, missing timezone, stray characters, or copy-pasting a human-readable expiry.
Related errors
- Invalid --ttl-days value: ${opts.ttlDays}
- Invalid --adapter-override "${raw}". Use slug=type.
- Invalid ${flag} "${raw}". Use ${format}.
- Failed to create board API key
- Agent reference is required
AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12).
Data as JSON: /api/errors/289c9230d44dcf60.
Report an issue: GitHub.