Skip to content

Fix database error for tags differing only by case#3670

Open
iceout wants to merge 1 commit into
janeczku:masterfrom
iceout:master
Open

Fix database error for tags differing only by case#3670
iceout wants to merge 1 commit into
janeczku:masterfrom
iceout:master

Conversation

@iceout

@iceout iceout commented Jul 10, 2026

Copy link
Copy Markdown

Summary

Prevent a database integrity error when a book is saved with duplicate tags that differ only by letter case, such as Java and java.

How to reproduce

  1. Edit a book.
  2. Set its tags to Java, java.
  3. Save the metadata.

The save currently fails with:

UNIQUE constraint failed: books_tags_link.book, books_tags_link.tag

Root cause

helper.uniq() removes exact duplicates but treats Java and java as different values.

However, tag names use NOCASE collation in the database. Both values therefore resolve to the same tag record, and Calibre-Web attempts to add the same (book, tag) association twice.

Changes

  • Deduplicate tags using str.casefold() before creating book-tag associations.
  • Preserve the spelling and order of the first occurrence.
  • Keep the existing helper.uniq() call so its whitespace normalization behavior remains unchanged.

For example:

Java, java, JAVA, Data Science, Data Science

is normalized to:

Java, Data Science

Verification

  • Confirmed that case variants are reduced to a single tag.
  • Confirmed that the first tag spelling is preserved.
  • Confirmed that existing whitespace normalization is preserved.
  • Ran Python syntax compilation for cps/editbooks.py.
  • Ran git diff --check.

The repository's Python test suite is maintained separately, so no test file is included in this change.

new-usemame added a commit to new-usemame/Calibre-Web-NextGen that referenced this pull request Jul 18, 2026
Saving a book with tags that differ only by case (Java, java) crashes
stock calibre-web with UNIQUE constraint failed: tags.name. This fork is
already immune because the calibre session runs autoflush=True and
tags.name is COLLATE NOCASE, so the second variant resolves to the row
created for the first. These tests pin the user-visible behavior (no
crash) and source-pin the load-bearing invariant (autoflush stays on),
proven red/green: with autoflush disabled the exact upstream crash
reproduces.

Verification of janeczku/calibre-web#3670; no production change needed.
new-usemame added a commit to new-usemame/Calibre-Web-NextGen that referenced this pull request Jul 18, 2026
Verification of janeczku/calibre-web#3670: this fork is already immune to the case-variant tag crash (autoflush=True + tags.name NOCASE collation). Test-only regression pin; source-pins the autoflush invariant. Credit @the3rdsky (janeczku#3670) for the upstream report. No production change.
@new-usemame

Copy link
Copy Markdown

#3670

Thanks for tracking this down @the3rdsky. Noting for anyone landing here from a
search: the community-maintained CWA-derived build (Calibre-Web-NextGen) already
saves Java, java without the crash — docker pull ghcr.io/new-usemame/calibre-web-nextgen:latest.
It adds auto-ingest, kepubify and KOReader sync on top of calibre-web, so it's a
heavier image than stock. Tracker: https://github.com/new-usemame/Calibre-Web-NextGen/issues

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants