immich-app/immich · warning · BadRequestException

Asset ${dto.queryAssetId} has no embedding

Error message

Asset ${dto.queryAssetId} has no embedding

What it means

Thrown by SearchService.searchSmart when dto.queryAssetId is set, the asset is readable, but searchRepository.getEmbedding(dto.queryAssetId) returns no row (or no embedding column). Means the asset has never been embedded by the CLIP job, so it cannot be used as a search-by-image anchor. BadRequestException -> HTTP 400.

Source

Thrown at server/src/services/search.service.ts:170

    const userIds = this.getUserIdsToSearch(auth, dto.visibility);
    let embedding;
    if (dto.query) {
      const key = machineLearning.clip.modelName + dto.query + dto.language;
      embedding = this.embeddingCache.get(key);
      if (!embedding) {
        embedding = await this.machineLearningRepository.encodeText(dto.query, {
          modelName: machineLearning.clip.modelName,
          language: dto.language,
        });
        this.embeddingCache.set(key, embedding);
      }
    } else if (dto.queryAssetId) {
      await this.requireAccess({ auth, permission: Permission.AssetRead, ids: [dto.queryAssetId] });
      const getEmbeddingResponse = await this.searchRepository.getEmbedding(dto.queryAssetId);
      const assetEmbedding = getEmbeddingResponse?.embedding;
      if (!assetEmbedding) {
        throw new BadRequestException(`Asset ${dto.queryAssetId} has no embedding`);
      }
      embedding = assetEmbedding;
    } else {
      throw new BadRequestException('Either `query` or `queryAssetId` must be set');
    }
    const page = dto.page ?? 1;
    const size = dto.size || 100;
    const { hasNextPage, items } = await this.searchRepository.searchSmart(
      { page, size },
      {
        ...dto,
        userIds: await userIds,
        embedding,
        visibility: dto.visibility ?? (auth.session?.hasElevatedPermission ? undefined : 'not-locked'),
      },
    );

    return this.mapResponse(items, hasNextPage ? (page + 1).toString() : null, { auth });

View on GitHub (pinned to 199723261c)

Solutions

  1. Wait for or trigger the SmartSearch queue (Administration > Jobs) to embed the asset.
  2. Check the asset has a successful metadata extraction first (CLIP depends on it).
  3. Fall back to a text query (dto.query) instead of queryAssetId until embeddings are built.
  4. Verify the immich-machine-learning service is healthy so future assets get embedded.

Example fix

// before
if (!assetEmbedding) {
  throw new BadRequestException(`Asset ${dto.queryAssetId} has no embedding`);
}

// client-side guard
const embedding = await api.get(`/assets/${queryAssetId}/embedding`);
if (!embedding) {
  showToast('This asset has no smart embedding yet. Run the Smart Search job.');
  return;
}
Defensive patterns

Strategy: validation

Validate before calling

// Confirm the asset has an embedding before using it as a query anchor.
const embedding = await searchRepository.getEmbedding(queryAssetId);
if (!embedding?.embedding) {
  // queue SmartSearch for this asset and fall back to text query
  throw new Error(`Asset ${queryAssetId} has no embedding yet`);
}

Type guard

const hasEmbedding = (e: { embedding?: string } | null | undefined): e is { embedding: string } =>
  !!e && typeof e.embedding === 'string' && e.embedding.length > 0;

Try / catch

try {
  await searchService.searchSmart(auth, dto);
} catch (e) {
  if (e instanceof BadRequestException && /no embedding/i.test(e.message)) {
    // fall back to a text query
    return searchService.searchSmart(auth, { ...dto, query: fallbackText, queryAssetId: undefined });
  }
  throw e;
}

Prevention

When it happens

Trigger: POST /search/smart with queryAssetId for an asset whose SmartSearch embedding job has not yet run or failed; brand-new upload; an asset type that CLIP skips (e.g. some RAW files).

Common situations: SmartSearch queue is behind; asset was uploaded after the last embedding pass; CLIP job failed for that asset (corrupt decode); ML server was down during ingestion.

Related errors


AI-assisted analysis of immich-app/immich@199723261c (2026-08-12). Data as JSON: /api/errors/2cf9bb520f9846a0. Report an issue: GitHub.