Skip to content

Report a missing key as NA rather than failing - #312

Closed
BenjaminDEMAILLE wants to merge 1 commit into
satijalab:mainfrom
BenjaminDEMAILLE:fix/key-without-key
Closed

BenjaminDEMAILLE wants to merge 1 commit into
satijalab:mainfrom
BenjaminDEMAILLE:fix/key-without-key

Conversation

@BenjaminDEMAILLE

Copy link
Copy Markdown

Fixes #41, and the DotPlot variant @boluofen reported in the same thread.

Error in vapply(X = keyed.objects, FUN = function(x) { :
  values must be length 1, but FUN(X[[2]]) result is length 0

Cause

Key.Seurat() vapplies over the keyed members with FUN.VALUE = character(1):

vapply(
  X = .FilterObjects(object = object, classes.keep = c('SpatialImage', 'KeyMixin')),
  FUN = \(x) Key(object = object[[x]]),
  FUN.VALUE = character(length = 1L),
  USE.NAMES = TRUE
)

A member carrying no key at all returns character(0), so the whole call fails. Key() is called by FetchData(), which is why this surfaces as a failure of FeatureScatter, DotPlot, or anything else that fetches, with a message that names neither the object nor the key.

Objects built before keys were enforced still carry keyless members, and they load without complaint, so nothing signals the problem until something asks for a key. That matches the reports here: an assay brought in from another package, in an object that otherwise behaves.

Fix

Return NA_character_ for a member with no key. NA is already what the rest of the code expects for one; [[<- checks is.na(object.keys[i]) when resolving duplicate keys. Key() then returns a full vector, FetchData() works, and the keyless member is visible as NA rather than fatal.

Tests

tests/testthat/test_key_missing.R: Key() and Keys() on an object whose second assay has had its key removed, FetchData() on the same object, and keys unchanged when every member has one.

Two assertions fail without the change. SeuratObject suite: 184 passing, 0 failures. Seurat's own suite against this build: 1184 passing, the only 2 failures being ones that predate it and are unrelated (Read10X_Image, satijalab/seurat#10454).

🤖 Generated with Claude Code

Key.Seurat() vapplies over the keyed members with FUN.VALUE character(1),
so a member carrying no key returns length 0 and the whole call fails:

  Error in vapply(X = keyed.objects, FUN = function(x) { :
    values must be length 1, but FUN(X[[2]]) result is length 0

Since Key() is called by FetchData(), that takes down everything that
fetches or plots, and the message names neither the object nor the key.

Objects made before keys were enforced still carry keyless members, and
they load without complaint, so the object looks fine until something
asks for a key.

Return NA_character_ for a member with no key. NA is already what the rest
of the code expects for one: `[[<-` checks `is.na(object.keys[i])` when
resolving duplicate keys.

Fixes satijalab#41.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@BenjaminDEMAILLE

Copy link
Copy Markdown
Author

Superseded by #318, which groups the correctness PRs into one so that a single review covers the subject. The commit is carried over unchanged; closing here to keep the queue down rather than because anything was wrong with it.

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.

The vapply error strikes again: values must be length 1, but FUN(X[[2]]) result is length 0 (Issue #1072)

1 participant