thedotmack/claude-mem · error
server job ID must not contain
Error message
server job ID must not contain ':' (got ${jobId}) What it means
ServerJobQueue.add() validates job IDs before enqueueing into BullMQ. Redis/BullMQ job IDs are used in key names, and ':' is the key separator, so an ID containing ':' would corrupt key structure. The queue rejects such IDs up front with this error.
Solutions
- Remove or replace ':' in the jobId before calling add (e.g. use '-' or '_' as separator)
- Use a library-provided sanitizer/encoder such as encodeURIComponent or a hash of the composite parts
- If a composite identifier is needed, pass its parts in the job payload instead of the ID
Example fix
// before
await queue.add(`${tenantId}:${jobType}:${uuid}`, payload);
// after
await queue.add(`${tenantId}--${jobType}--${uuid}`, payload); Defensive patterns
Strategy: validation
Validate before calling
if (typeof jobId === 'string' && !jobId.includes(':')) {
await queue.add(jobId, payload, options);
} else {
throw new Error(`jobId must not contain ':': ${jobId}`);
} Type guard
const isSafeJobId = (id: unknown): id is string =>
typeof id === 'string' && id.length > 0 && !id.includes(':'); Try / catch
try {
await queue.add(jobId, payload, options);
} catch (e) {
if (e instanceof Error && e.message.includes("must not contain ':'")) {
// sanitize and retry or log a config error
}
throw e;
} Prevention
- Derive job IDs from a single safe alphabet (UUIDs, hex)
- Join composite key parts with '-' or '_' instead of ':'
- Add a unit test asserting generated IDs contain no ':'
When it happens
Trigger: Calling add(jobId, payload, options) with a jobId string that includes the ':' character, e.g. 'tenant:123:job' or a composite 'type:id' identifier.
Common situations: Building composite IDs by joining tenant/user IDs with ':'; passing a Redis key or BullMQ queue name as the jobId; using a serialized object string containing colons as an ID.
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
- BullMQ re-enqueue failed (will reconcile on startup)
- CLAUDE_MEM_REDIS_URL must use redis:// or rediss://
- Invalid CLAUDE_MEM_REDIS_MODE=
- Invalid CLAUDE_MEM_REDIS_PORT=
- invalid_ops: deviceId must be 1-128 characters
AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17).
Data as JSON: /api/errors/95a5332116fe6c8c.
Report an issue: GitHub.
Appendix: source
Thrown at src/server/jobs/ServerJobQueue.ts:141
: new Queue<TPayload>(this.name, queueOptions);
return this.queue;
}
private async addToQueue(jobId: string, payload: TPayload, options?: JobsOptions): Promise<void> {
await (this.getQueue().add as (
name: string,
data: TPayload,
opts?: JobsOptions
) => Promise<unknown>)(this.name, payload, {
...this.defaultJobOptions,
...options,
jobId
});
}
async add(jobId: string, payload: TPayload, options?: JobsOptions): Promise<void> {
if (jobId.includes(':')) {
throw new Error(`server job ID must not contain ':' (got ${jobId})`);
}
try {
await this.addToQueue(jobId, payload, options);
} catch (error) {
const err = error instanceof Error ? error : new Error(String(error));
throw this.toRedisUnavailableError(err);
}
}
async getJob(jobId: string): Promise<Job<TPayload> | null | undefined> {
try {
return (await this.getQueue().getJob(jobId)) as Job<TPayload> | null | undefined;
} catch (error) {
const err = error instanceof Error ? error : new Error(String(error));
throw this.toRedisUnavailableError(err);
}
}
View on GitHub (pinned to d8bc9755e7)