hankcs/HanLP · error · ValueError

Expect X to be 2 or 3 elements but got {repr(X)}

Error message

Expect X to be 2 or 3 elements but got {repr(X)}

What it means

X_to_inputs expects the feature batch X to be a 2-tuple (forms, cposes) or 3-tuple (forms, cposes, mask), matching the TF parsing model's output arrangement. Any other length triggers this ValueError.

Source

Thrown at hanlp/transform/conll_tf.py:55

    def use_pos(self):
        return self.config.get('use_pos', True)

    def x_to_idx(self, x) -> Union[tf.Tensor, Tuple]:
        form, cpos = x
        return self.form_vocab.token_to_idx_table.lookup(form), self.cpos_vocab.token_to_idx_table.lookup(cpos)

    def y_to_idx(self, y):
        head, rel = y
        return head, self.rel_vocab.token_to_idx_table.lookup(rel)

    def X_to_inputs(self, X: Union[tf.Tensor, Tuple[tf.Tensor]]) -> Iterable:
        if len(X) == 2:
            form_batch, cposes_batch = X
            mask = tf.not_equal(form_batch, 0)
        elif len(X) == 3:
            form_batch, cposes_batch, mask = X
        else:
            raise ValueError(f'Expect X to be 2 or 3 elements but got {repr(X)}')
        sents = []

        for form_sent, cposes_sent, length in zip(form_batch, cposes_batch,
                                                  tf.math.count_nonzero(mask, axis=-1)):
            forms = tolist(form_sent)[1:length + 1]
            cposes = tolist(cposes_sent)[1:length + 1]
            sents.append([(self.form_vocab.idx_to_token[f],
                           self.cpos_vocab.idx_to_token[c]) for f, c in zip(forms, cposes)])

        return sents

    def lock_vocabs(self):
        super().lock_vocabs()
        self.puncts = tf.constant([i for s, i in self.form_vocab.token_to_idx.items()
                                   if ispunct(s)], dtype=tf.int64)

    def file_to_inputs(self, filepath: str, gold=True):
        assert gold, 'only support gold file for now'

View on GitHub (pinned to ddb1299bdd)

Solutions

  1. Pack X as exactly (form_batch, cposes_batch) or (form_batch, cposes_batch, mask).
  2. Check the upstream component that produced X — a mismatch usually means you are feeding data from the wrong model/stage.
  3. Verify no extra element (e.g. lemma features) was appended to X.

Example fix

# before
inputs = transform.X_to_inputs([forms, cposes, mask, lemmas])
# after
inputs = transform.X_to_inputs([forms, cposes, mask])
Defensive patterns

Strategy: type-guard

Validate before calling

assert isinstance(X, (list, tuple)) and len(X) in (2, 3), 'X must be (forms, cposes[, mask])'

Type guard

def is_valid_X(X):
    return isinstance(X, (list, tuple)) and len(X) in (2, 3) and hasattr(X[0], 'shape')

Prevention

When it happens

Trigger: Calling XY_to_inputs_outputs/X_to_inputs with an X that is a list/tuple of length other than 2 or 3, e.g. feeding raw tensors, a single stacked tensor, or a 4-element tuple with extra features.

Common situations: Changing the model's feature layout without updating the transform; passing numpy arrays from a different pipeline; hand-crafting inputs for the TF parser.

Related errors


AI-assisted analysis of hankcs/HanLP@ddb1299bdd (2026-08-27). Data as JSON: /api/errors/ec58b9a566c5f116. Report an issue: GitHub.