immich-app/immich · error · BadRequestException

Invalid assetIds

Error message

Invalid assetIds

What it means

For SharedLinkType.Individual, SharedLink.create requires a non-empty assetIds array; without it the link would share nothing. An empty or missing array triggers BadRequestException('Invalid assetIds') before the per-asset share permission check.

Solutions

  1. Provide at least one asset id in assetIds for Individual links.
  2. Disable/validate the submit action when the asset selection is empty.
  3. Use type Album with an albumId if the intent is sharing a whole album.

Example fix

// before
await api.createSharedLink({ type: SharedLinkType.Individual, assetIds: [] });
// after
await api.createSharedLink({ type: SharedLinkType.Individual, assetIds: selectedAssetIds });
Defensive patterns

Strategy: validation

Validate before calling

if (dto.type === SharedLinkType.Individual && (!dto.assetIds || dto.assetIds.length === 0)) {
  throw new Error('Individual shared links require at least one assetId');
}

Type guard

const hasAssets = (dto) =>
  Array.isArray(dto.assetIds) && dto.assetIds.length > 0 && dto.assetIds.every((id) => typeof id === 'string');

Try / catch

try {
  await api.createSharedLink(dto);
} catch (e) {
  if (e.status === 400 && e.message === 'Invalid assetIds') {
    // prompt: select at least one asset
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: POST /shared-links with dto.type = SharedLinkType.Individual and dto.assetIds undefined, null, or an empty array.

Common situations: User deselects all assets in the share dialog but proceeds; batch selection lost on page navigation; asset list filtered to zero items before building the payload.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15). Data as JSON: /api/errors/af69042f5bcaed61. Report an issue: GitHub.

Appendix: source

Thrown at server/src/services/shared-link.service.ts:81

  async get(auth: AuthDto, id: string): Promise<SharedLinkResponseDto> {
    const sharedLink = await this.findOrFail(auth.user.id, id);
    return mapSharedLink(sharedLink, { stripAssetMetadata: false });
  }

  async create(auth: AuthDto, dto: SharedLinkCreateDto): Promise<SharedLinkResponseDto> {
    switch (dto.type) {
      case SharedLinkType.Album: {
        if (!dto.albumId) {
          throw new BadRequestException('Invalid albumId');
        }
        await this.requireAccess({ auth, permission: Permission.AlbumShare, ids: [dto.albumId] });
        break;
      }

      case SharedLinkType.Individual: {
        if (!dto.assetIds || dto.assetIds.length === 0) {
          throw new BadRequestException('Invalid assetIds');
        }

        await this.requireAccess({ auth, permission: Permission.AssetShare, ids: dto.assetIds });

        break;
      }
    }

    try {
      const sharedLink = await this.sharedLinkRepository.create({
        key: this.cryptoRepository.randomBytes(50),
        userId: auth.user.id,
        type: dto.type,
        albumId: dto.albumId || null,
        assetIds: dto.assetIds,
        description: dto.description || null,
        password: dto.password,
        expiresAt: dto.expiresAt || null,

View on GitHub (pinned to e55ac299a4)