Skip to content

Tolerate broken image files per-item during embedding#1564

Open
JonasWurst wants to merge 1 commit into
jonas-lig-10034-prefactor-keyed-embedding-resultfrom
jonas-lig-10034-image-embedding-tolerate-broken-files-per-item-instead-of
Open

Tolerate broken image files per-item during embedding#1564
JonasWurst wants to merge 1 commit into
jonas-lig-10034-prefactor-keyed-embedding-resultfrom
jonas-lig-10034-image-embedding-tolerate-broken-files-per-item-instead-of

Conversation

@JonasWurst

Copy link
Copy Markdown
Contributor

What

LIG-10034. A single un-decodable image no longer crashes the whole embedding batch. Broken files are skipped per-item, recorded as broken in a per-run FileOutcomeReport, and left without an embedding row (no placeholder); the rest of the batch still embeds. The all-failed rule (LIG-10029) still raises when every attempted file fails.

Stacked on #1563 — review/merge that first. This PR targets the prefactor branch; the diff here is only the tolerance behavior.

How

  • Shared decode boundary open_image_as_rgb translates decode failures into BrokenInputFileError (raise ... from e). Both the full-image and image-crop paths route decodes through it — one typed-error contract, not three bespoke catch-alls. Unexpected exceptions propagate.
  • Image path (DataLoader): decode runs inside the worker, so __getitem__ returns the typed error alongside the input index; the main-process collation re-raises it inside report.track so the outcome is recorded there. Good items in the batch are still stacked and encoded.
  • Crop path: decode each source file inside report.track; a broken source file is recorded once and all its crops are skipped.
  • Manager: owns the FileOutcomeReport, applies raise_if_all_failed + log_summary (embed_annotations shares one report across chunks). compute_image_embedding raises on a broken single file.

Because results are keyed by sample id (the prefactor), skipping a broken file just omits its id from keys — no index bookkeeping.

Acceptance criteria

  • A broken image mid-batch is skipped, not fatal; remaining images still embed.
  • The skipped image is recorded as broken via BrokenInputFileError routed through the helper.
  • No placeholder/empty embedding row for the skipped sample.
  • All three decode sites share one typed-error contract + helper; unexpected exceptions not swallowed.
  • The worker→main-process outcome-collection mechanism is implemented and documented.
  • Test: a batch with one corrupt image yields embeddings for the good images and a broken record for the bad one.

🤖 Generated with Claude Code

LIG-10034. A single un-decodable image no longer crashes the whole embedding
batch. Broken files are skipped per-item, recorded as broken in a per-run
FileOutcomeReport, and left without an embedding row (no placeholder); the rest
of the batch still embeds. The all-failed rule (LIG-10029) still raises when
every attempted file fails.

- Add shared open_image_as_rgb decode boundary that translates decode failures
  into BrokenInputFileError (raise ... from e). Both the full-image and
  image-crop paths route decodes through it, one typed-error contract.
- image_embedding: decode runs inside the DataLoader worker, so __getitem__
  returns the typed error alongside the input index; the main-process collation
  re-raises it inside report.track so the outcome is recorded there. Good items
  in the batch are still stacked and encoded.
- image_crop_embedding: decode each source file inside report.track; a broken
  source file is recorded once and all its crops are skipped.
- embedding_manager: own the FileOutcomeReport, apply raise_if_all_failed +
  log_summary (embed_annotations shares one report across chunks).
  compute_image_embedding raises on a broken single file.

Because results are keyed by sample id (the prefactor), skipping a broken file
just omits its key from the result — no index bookkeeping.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@JonasWurst JonasWurst requested a review from a team as a code owner July 3, 2026 13:16
@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e74a2217-e569-4bb6-9ab7-d99bbaa593b0

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jonas-lig-10034-image-embedding-tolerate-broken-files-per-item-instead-of

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 187035ee9c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +51 to +52
except (OSError, UnidentifiedImageError) as exc:
raise BrokenInputFileError(f"Could not decode image '{filepath}'.") from exc

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve missing-file failures instead of marking them broken

OSError also includes FileNotFoundError, so when an embedding job references a deleted image (or an fsspec backend raises not-found while opening), this helper converts it to BrokenInputFileError; report.track then suppresses it and continues without an embedding row. That widens the new tolerance from undecodable images to missing/IO failures and misreports them as broken, despite the existing outcome contract having MissingInputFileError for missing paths. Check existence before this catch or narrow the caught exceptions.

Useful? React with 👍 / 👎.

from lightly_studio.core.file_outcome_report import FileOutcomeReport
from lightly_studio.dataset.embedding_generator import BatchedEmbeddingResult, ImageCrop
from lightly_studio.dataset.image_embedding import EmbeddingContext
from lightly_studio.dataset.image_embedding import EmbeddingContext, open_image_as_rgb

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Import the image helper through its module

The Python guideline in AGENTS.md says functions should be imported via the containing module and called with dot notation, while classes may be imported directly. This new direct function import violates that convention; import the image_embedding module and call image_embedding.open_image_as_rgb(...) instead.

Useful? React with 👍 / 👎.

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.

1 participant