Skip to content

server: Requires at least one start in AI/full mode even for sync-only #87

Description

@MarcelWaldvogel

Component

Sync server

Version / commit

Docker image 38ea48eaefe3

What happened?

A Quire (docker) server started from the beginning with QUIRE_SERVER_AI_ENABLED=false will not work, as SQL queries rely on the presence of book_themes.

Starting the Quire server once with QUIRE_SERVER_AI_ENABLED=true applies the necessary migrations.

Proposed fixes (either is fine):

  • Apply the migrations anyway, even when AI is disabled, or
  • only query the AI tables when AI is currently enabled.

Reproduction steps

  1. Set up a fresh Quire docker server with QUIRE_SERVER_AI_ENABLED=false from the start (with a fresh database).
  2. Querying the /library/v1/stats endpoint (and other endpoints) resulted in HTTP 500.
  3. The logs reveal that the authentication request to calibre-web succeeds (200), but PostgreSQL complains about relation "book_themes" does not exist.
  4. Restarting the Quire docker server once with QUIRE_SERVER_AI_ENABLED=true fixes the problem, even when later switching back to false

Logs

quire-server-1  | INFO:httpx:HTTP Request: GET https://calibre.example.com/opds "HTTP/1.1 200 OK"
postgres-1      | 2026-07-12 10:02:46.534 UTC [57] ERROR:  relation "book_themes" does not exist at character 756
postgres-1      | 2026-07-12 10:02:46.534 UTC [57] STATEMENT:  SELECT book_themes.theme AS theme, count(distinct(picked_insight.library_item_pk)) AS c 
postgres-1      | 	FROM (SELECT DISTINCT ON (library_items.pk) library_items.pk AS library_item_pk, book_insights.id AS book_insight_id 
postgres-1      | 	FROM library_items JOIN book_insights ON book_insights.superseded_at IS NULL AND (book_insights.metadata_id IS NOT NULL AND book_insights.metadata_id = library_items.metadata_id OR book_insights.content_hash = library_items.content_hash) 
postgres-1      | 	WHERE library_items.user_id = $1::VARCHAR AND library_items.deleted_at IS NULL ORDER BY library_items.pk, CASE WHEN (book_insights.metadata_id IS NOT NULL AND book_insights.metadata_id = library_items.metadata_id) THEN $2::INTEGER ELSE $3::INTEGER END, book_insights.generated_at DESC) AS picked_insight JOIN book_themes ON book_themes.book_insight_id = picked_insight.book_insight_id 
postgres-1      | 	WHERE book_themes.confidence >= $4::FLOAT GROUP BY book_themes.theme ORDER BY count(distinct(picked_insight.library_item_pk)) DESC, book_themes.theme ASC 
postgres-1      | 	 LIMIT $5::INTEGER

Device / OS (Android only)

Docker

calibre-web version

0.6.26

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions