immich-app/immich · critical

The extension is not available in this Postgres instance…

Error message

The ${name} extension is not available in this Postgres instance.
    If using a container image, ensure the image has the extension installed.

What it means

During bootstrap, each required vector extension (vectorchord/pgsql-vectorchord or pgvector per EXTENSION_NAMES) is checked via getExtensionVersions. If pg_available_extensions reports no available version, the extension is not installed in the Postgres image, so Immich aborts startup with messages.notInstalled(name).

Solutions

  1. Use the official Immich Postgres image (ghcr.io/immich-app/postgres or tensorchord pgvecto-rs image) that bundles the extension.
  2. Install the required extension package into your Postgres instance and ensure CREATE EXTENSION can find it (shared_preload_libraries for pgvecto.rs).
  3. Check DB_VECTOR_EXTENSION config points at an extension actually present in the image.

Example fix

// before
image: postgres:15
// after
image: ghcr.io/immich-app/postgres:15-vectorchord0.3.0
Defensive patterns

Strategy: validation

Validate before calling

const { rows } = await db.query("SELECT name FROM pg_available_extensions WHERE name IN ('vectorchord','vectors','pgvector')");
if (!rows.length) console.error('Postgres image lacks the required vector extension');

Try / catch

try {
  await server.start();
} catch (e) {
  if (/extension is not available/.test(e.message)) {
    console.error('Switch to the official Immich Postgres image that bundles', e.message);
  } else throw e;
}

Prevention

When it happens

Trigger: Starting Immich against a vanilla postgres image (e.g. postgres:15) that lacks the required vector extension, so no availableVersion exists for the configured extension.

Common situations: Swapping from tensorchord/pgvecto-rs image to stock postgres; missing image update after Immich release changed the required extension; extension name typo in DB environment config.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


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

Appendix: source

Thrown at server/src/services/database.service.ts:75

  async onBootstrap() {
    const version = await this.databaseRepository.getPostgresVersion();
    const current = coerce(version);
    const postgresRange = this.databaseRepository.getPostgresVersionRange();
    if (!current || !satisfies(current, postgresRange)) {
      throw new Error(
        `Invalid PostgreSQL version. Found ${version}, but needed ${postgresRange}. Please use a supported version.`,
      );
    }

    await this.databaseRepository.withLock(DatabaseLock.Migrations, async () => {
      const extension = await this.databaseRepository.getVectorExtension();
      const name = EXTENSION_NAMES[extension];
      const extensionRange = this.databaseRepository.getExtensionVersionRange(extension);

      const extensionVersions = await this.databaseRepository.getExtensionVersions(VECTOR_EXTENSIONS);
      const { installedVersion, availableVersion } = extensionVersions.find((v) => v.name === extension) ?? {};
      if (!availableVersion) {
        throw new Error(messages.notInstalled(name));
      }

      if ([availableVersion, installedVersion].some((version) => version && eq(version, '0.0.0'))) {
        throw new Error(messages.nightlyVersion({ name, extension, version: '0.0.0' }));
      }

      if (!satisfies(availableVersion, extensionRange)) {
        throw new Error(messages.outOfRange({ name, extension, version: availableVersion, range: extensionRange }));
      }

      if (!installedVersion) {
        await this.createExtension(extension);
      }

      if (installedVersion && gt(availableVersion, installedVersion)) {
        await this.updateExtension(extension, availableVersion);
      } else if (installedVersion && !satisfies(installedVersion, extensionRange)) {
        throw new Error(messages.outOfRange({ name, extension, version: installedVersion, range: extensionRange }));

View on GitHub (pinned to e55ac299a4)