Skip to content

cross-provider author-identity/duplicate behaviour #2117

Closed

Description

@TheOpsMgr

Pre-flight

  • I searched existing issues and this isn't a duplicate
  • I'm running the latest version (check Settings → About)

Current behaviour

Duplicate authors are created when OpenLibrary author looked fails and author fetching fails over to DNB.

Expected behaviour

Authors should be automatically de-duped when OpenLibrary queries come back online.

Steps to reproduce

  1. spoof OpenLibrary being offline via hosts end or firewall block
  2. import author.csv file that contains some existing authors to trigger author fetch process
  3. see that duplicate authors are created
Image

Trace logs

08/19, 10:11:38 | WARN |   | metadata search: provider failed | error="search authors: openlibrary request: Get \"https://openlibrary.org/search/authors.json?q=Adam+Roberts&limit=20\": context deadline exceeded" provider=openlibrary -- | -- | -- | -- | -- 
08/19, 10:11:35 | ERROR |   | failed to fetch books | author="Adrian Tchaikovsky" error="dnb get author works dnb:1394981503: Get \"https://services.dnb.de/sru/dnb?maximumRecords=50&operation=searchRetrieve&query=per%3D1394981503&recordSchema=MARC21-xml&version=1.1\": context canceled" 
08/19, 10:11:35 | WARN |   | author profile refresh: metadata lookup failed | author="Adrian Tchaikovsky" error="dnb does not support author lookup by ID" foreignId=dnb:1394981503 
08/19, 10:11:35 | INFO |   | fetching books for author | author="Adrian Tchaikovsky" foreignId=dnb:1394981503 
08/19, 10:11:35 | WARN |   | metadata search: provider failed | error="search authors: openlibrary request: Get \"https://openlibrary.org/search/authors.json?q=Adrian+Tchaikovsky&limit=20\": context deadline exceeded" provider=openlibrary

Deployment method

Docker (ghcr.io)

Bindery version

1.32.0

Environment details

No response

Activity

  1. TheOpsMgr commented on Aug 20, 2026

    @TheOpsMgr
    Author

    Related Issue and analysis

    Your duplicate author theory is right, and I found the mechanism. You worked it out from log symptoms, which was a good call.
    
    Aggregator.SearchAuthors fans out across every configured provider and only returns an error when none of them succeeded. So when OpenLibrary is timing out and DNB answers, the search reports success and the top match can be a DNB record carrying a DNB foreign id. The CSV importer then sets the provider on the new author unconditionally:
    
    full.MetadataProvider = "openlibrary"
    regardless of which provider actually produced the match. The row gets stored with a DNB key while claiming to be an OpenLibrary author. Later, once OpenLibrary is answering again, the same person resolves to a real OL key, the existing row lookup by that key misses the DNB keyed one, and you get a second author. Precisely what you described.
    
    The mislabelling is the part that bothers me most. Anything that reads MetadataProvider to work out how to interpret ForeignID is now being lied to, so the duplicate is the visible symptom rather than the whole problem.
    
    Yes please on splitting that out, since you offered. It's a distinct root cause from the rate limiting and it'll get fixed on its own timeline. Dropping needs-triage here.
    
    On the outage theory: plausible as a trigger and it may well be why this surfaced now, but it doesn't change the diagnosis. Nineteen authors fanning out per work and per edition with no cap and no backoff was always going to storm them eventually. A tighter limit upstream just moved the point where it broke.
    
  2. vavallee commented on Aug 20, 2026

    @vavallee
    Owner

    Add Steps to reproduce (minimal numbered sequence), the Bindery version from Settings → About, and a Trace logs section captured with the runtime log level set to DEBUG in Settings → Logs (or BINDERY_LOG_LEVEL=debug). Issues without logs may be closed without investigation.

    — 🤖 bindhelper (automated). Reply to correct me; a human reviews every change.

  3. TheOpsMgr commented on Aug 20, 2026

    @TheOpsMgr
    Author

    Add Steps to reproduce (minimal numbered sequence), the Bindery version from Settings → About, and a Trace logs section captured with the runtime log level set to DEBUG in Settings → Logs (or BINDERY_LOG_LEVEL=debug). Issues without logs may be closed without investigation.

    — 🤖 bindhelper (automated). Reply to correct me; a human reviews every change.

    trace logs are available on the linked issue.

  4. vavallee commented on Sep 5, 2026

    @vavallee
    Owner

    You are right and the bot should not have asked. Your trace logs were on #2075 the whole time, you said so, and then this went quiet. Sorry about that.

    I traced it. The mechanism is two separate defects stacking:

    Aggregator.SearchAuthorsWithOutcome (internal/metadata/aggregator.go:74) fans out across providers and only returns an error when every one of them fails (:90). So with OpenLibrary timing out and DNB answering, the search reports success and hands back a DNB record. #2271 added a guard for exactly this, SearchOutcome.SafeToBind, which refuses to write a permanent provider link when the primary dropped out of the search. It is wired into the Audiobookshelf import and the author relink paths. It was never wired into the CSV, Readarr or Goodreads importers.

    On top of that, those three importers hardcode the provider label: internal/migrate/csv.go:175, internal/migrate/readarr.go:133 and internal/migrate/goodreads.go:349 all set MetadataProvider = "openlibrary" regardless of which provider actually answered. So the row ends up with a dnb: foreign ID while claiming to be an OpenLibrary author. Since catalogue fetches route off the foreign ID prefix rather than the label, the two disagree and the label is the one that is wrong.

    That is your duplicates. Once OpenLibrary is answering again, a lookup by the real OpenLibrary key misses the row bound under the DNB key and creates a second author for the same person.

    Filed as #2332 with both halves. The reconciliation question, meaning what to do about rows already written this way, I have left out of that issue deliberately, because it needs a different answer from the prevention. Until then, Merge on the author page is the way to collapse a pair: open the one you want to keep, Merge, pick the duplicate as the source. It moves the books over and records the source's name as an alias, so it stays merged across future imports.

  5. added
    area:metadataMetadata providers and matching
    and removed
    needs-triageNew issue, not yet reviewed
    on Oct 8, 2026
  6. vavallee commented on Oct 8, 2026

    @vavallee
    Owner

    Fixed in v1.41.0. An author import no longer binds to a fallback provider while OpenLibrary is down (#2610), and re-running an import now skips an author you already have under another provider instead of adding a second one (#3106). Duplicates made before this stay until merged: open the one to keep, Merge, and pick the other as the source. Thanks for the clear report and the logs.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:metadataMetadata providers and matchingbugSomething isn't workingpriority:mediumReal bug with a workaround

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions