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

  1. Remove or replace ':' in the jobId before calling add (e.g. use '-' or '_' as separator)
  2. Use a library-provided sanitizer/encoder such as encodeURIComponent or a hash of the composite parts
  3. 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

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


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)