Skip to content

Validate select fields before model loading to prevent cryptic crashes - #168

Merged
arjunrajlab merged 4 commits into
masterfrom
claude/docker-network-resolution-tnfkan
Aug 7, 2026
Merged

Validate select fields before model loading to prevent cryptic crashes#168
arjunrajlab merged 4 commits into
masterfrom
claude/docker-network-resolution-tnfkan

Conversation

@arjunrajlab

Copy link
Copy Markdown
Collaborator

Summary

Adds validation for select interface fields (particularly model selections) before they are used in model loading or checkpoint path construction. This prevents cryptic crashes deep inside model loaders when a saved tool config holds null or a stale model name.

Problem

A production sam_fewshot_segmentation job crashed with FileNotFoundError: [Errno 2] No such file or directory: '/None.pth' because the saved tool config held "Model": null. The null value was silently used to build the checkpoint path, and the job died deep inside SAM's model loader with no indication that the model selection was the problem.

Additionally, configs saved against older worker images can name model checkpoints that no longer exist in the current image, leading to similar downstream failures.

Solution

  1. New utility function annotation_tools.get_required_select() validates that a select field value is:

    • Not None or empty/whitespace
    • A string (not a list, dict, or number)
    • In the allowed values list (if provided)

    Raises ValueError with a clear message directing users to re-select the field.

  2. Early validation in compute() functions across all affected workers:

    • Validates the model selection before any heavy imports or GPU setup
    • Checks that the checkpoint file exists on disk
    • Calls sendError() with a clear message on validation failure
    • Returns early to prevent downstream crashes
  3. Affected workers:

    • sam_fewshot_segmentation: validates against MODELS list
    • sam2_fewshot_segmentation, sam2_automatic_mask_generator, sam2_propagate, sam2_video, sam2_refine: validate against MODEL_TO_CFG mapping
    • stardist: validates against MODELS list
    • cellpose, cellposesam, piscis (predict/train), cellpose_train, cellposesam_train: validate model selections (some without static allowed values for custom models)

Key Changes

  • annotation_utilities/annotation_tools.py: Added get_required_select() function with comprehensive validation and user-friendly error messages
  • annotation_utilities/tests/test_required_select.py: New test file with 14 regression tests covering valid values, missing values, wrong types, and stale values
  • Worker entrypoints: Each affected worker now:
    • Extracts model selection early via get_required_select()
    • Validates against a static MODELS or MODEL_TO_CFG constant
    • Checks checkpoint file existence before loading
    • Calls sendError() on any validation failure
  • CLAUDE.md and .claude/skills/nimbus-worker-hardening/SKILL.md: Updated with guidance on the pitfall and the fix pattern
  • Test coverage: Added TestComputeModelValidation classes to sam_fewshot_segmentation and sam2_fewshot_segmentation test suites

Implementation Details

  • Validation happens before lazy imports of torch/model libraries, so failures are fast
  • Error messages include the field name and available options (when applicable)
  • The fix rejects null/stale values rather than silently substituting defaults, since the saved value is what the user believes the tool will run with
  • Workers with custom models from Girder (cellpose family, piscis) validate shape only—no static allowed_values list exists for those

https://claude.ai/code/session_01FFwLaqzmDWDnPuZvF6EL6m

A production sam_fewshot_segmentation job received '"Model": null' in its
saved tool config (a select field stores whatever was serialized when the
tool was saved, defaults notwithstanding), built the checkpoint path
'/None.pth' from it, and died with FileNotFoundError deep inside SAM's
model loader — after "Loading model" was already reported and with no hint
that the model selection was the problem.

Add annotation_tools.get_required_select(value, field_name, allowed_values)
which raises ValueError on null/empty/non-string select values and, when
given the valid options, on stale names from configs saved against older
worker images. Callers catch it and sendError so the user learns to
re-select the field and save the tool. Missing values are rejected rather
than silently replaced with the interface default, since substituting a
model changes the output.

Sweep every worker that builds a model/checkpoint from a select value:

- sam_fewshot_segmentation: validate against the static model list and
  check the checkpoint file exists, before the heavy torch/SAM imports so
  the job fails fast instead of after GPU setup.
- sam2_automatic_mask_generator, sam2_fewshot_segmentation, sam2_propagate,
  sam2_refine, sam2_video: hoist the copy-pasted model->config mapping to a
  MODEL_TO_CFG module constant, validate the selection against it (a null
  or stale name previously crashed with KeyError), and check checkpoint
  existence before build_sam2.
- stardist: validate against the static pretrained-model list.
- cellpose, cellposesam, piscis predict/train, cellpose_train,
  cellposesam_train: shape-validate only (custom models come from Girder,
  so there is no static option list), matching each worker's local
  sendError convention.

sam_automatic_mask_generator reads Model but never uses it, so it is left
alone. condensatenet already falls back safely via MODEL_PATHS.get().

Regression coverage: annotation_utilities/tests/test_required_select.py
(runs in CI) plus compute-level tests in sam_fewshot_segmentation and
sam2_fewshot_segmentation reproducing the production params. Document the
pitfall in CLAUDE.md and the nimbus-worker-hardening catalog.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFwLaqzmDWDnPuZvF6EL6m

@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: 325145ae90

ℹ️ 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 thread workers/annotations/sam_fewshot_segmentation/entrypoint.py
claude and others added 3 commits August 7, 2026 12:46
Address the Codex review on PR #168: the model-selection hardening changed
observable behavior in thirteen workers without touching their
hand-maintained docs.

- Add a "Model selection validation" section to all twelve affected worker
  docs (the shared PISCIS.md covers both predict and train), describing why
  null/stale select values are rejected, the sendError the user sees, and
  the remediation (re-select the model and save the tool). The wording is
  tailored per family: SAM1/SAM2 workers also verify checkpoint existence,
  stardist validates against its static list, and the cellpose/piscis
  family shape-validates only since custom models come from Girder.
- Add an explicit convention to CLAUDE.md and AGENTS.md: documentation
  updates ship with the change — any PR changing a worker's interface,
  behavior, outputs, or error handling must update the affected
  WORKERNAME.md in the same PR (the automated doc hooks are disabled, so
  this is a manual step).
- Sync the select-pitfall section into AGENTS.md, which mirrors CLAUDE.md
  but had not received it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFwLaqzmDWDnPuZvF6EL6m
Resolved the nimbus-worker-hardening SKILL.md conflict: both sides appended a
new catalog entry numbered 7. Kept master's groupby-on-empty-DataFrame entry as
#7 and renumbered the select-validation entry to #8. Mirrored #8 into the
.agents copy, which this branch had not updated.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Browser-testing the model-selection validation against a real dataset turned up
a regression in the seven sam*/stardist workers: sendError only prints a JSON
line for the frontend to render, it does not fail the job. Returning after it
left the job exit code 0, so Girder recorded a misconfigured run as SUCCESS.

Verified end to end on sam2_refine with a saved config holding 'Model': null:

  old image            job ERROR   'Job Failed, see the log' + KeyError: None
  new image, return    job SUCCESS clear error banner, wrong status
  new image, raise     job ERROR   clear error banner, correct status

A run that reports success but did nothing is worse than a crash, because
nobody goes looking for it. The cellpose/piscis workers already re-raised;
this brings the sam*/stardist workers in line. The checkpoint-missing guard
raises FileNotFoundError for the same reason.

Only the sites this branch added are changed; the pre-existing
sendError+return paths (no training tag, no training annotations) are left
alone. Tests updated to assert the raise, and docs/CLAUDE.md/AGENTS.md/skill
catalog updated to record why return is wrong here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@arjunrajlab
arjunrajlab force-pushed the claude/docker-network-resolution-tnfkan branch from 5af23c4 to 820bb22 Compare August 7, 2026 14:37
@arjunrajlab
arjunrajlab merged commit 9d28100 into master Aug 7, 2026
1 check passed
arjunrajlab added a commit that referenced this pull request Aug 7, 2026
Resolves three conflicts between this branch's dataset-aware `all` batch
parsing and master's batch-coordinate validation (#165) / select-field
validation (#168).

worker_client.py: master added `_parse_batch_values`, which reported
malformed Batch input with sendError before the clients were built. This
branch needs the dataset's IndexRange to expand `all`, so parsing has to
happen after datasetClient exists. Folded master's per-field error message
into the shared `get_batch_ranges()` so it raises a ValueError naming the
offending field, and WorkerClient catches it, sends the banner, and
re-raises. `_parse_batch_values` is gone; the direct SAM batching loops now
inherit the clear message too, which they never had.

CELLPOSESAM.md / CROP.md: kept master's more precise wording (1-indexed,
empty-selection error, size-one dimension note) and added this branch's
`all` documentation alongside it rather than replacing either.

Also mirrored the branch's skill updates into .claude/skills/, which it had
only applied to .agents/, and fixed the duplicate "### 7" the textual
auto-merge produced in the hardening catalog. Corrected the stale sweep
counts there (claimed ~6 WorkerClient / ~26 direct; actually 43 / 10).

Added two regression tests for the merged behavior: get_batch_ranges names
the field that failed to parse, and returns re-iterable lists rather than
one-shot generators.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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