hankcs/HanLP · error · InvalidTagSequence
" ".join(tag_sequence)
Error message
" ".join(tag_sequence)
What it means
bio_tags_to_spans requires every tag in the sequence to start with B, I or O. A tag like 'E-X', 'S-X', '' (empty), or a raw class name without a prefix raises InvalidTagSequence with the whole sequence.
Source
Thrown at hanlp/utils/span_util.py:348
A list of string class labels `excluding` the bio tag
which should be ignored when extracting spans.
# Returns
spans : `List[TypedStringSpan]`
The typed, extracted spans from the sequence, in the format (label, (span_start, span_end)).
Note that the label `does not` contain any BIO tag prefixes.
"""
classes_to_ignore = classes_to_ignore or []
spans: Set[Tuple[str, Tuple[int, int]]] = set()
span_start = 0
span_end = 0
active_conll_tag = None
for index, string_tag in enumerate(tag_sequence):
# Actual BIO tag.
bio_tag = string_tag[0]
if bio_tag not in ["B", "I", "O"]:
raise InvalidTagSequence(tag_sequence)
conll_tag = string_tag[2:]
if bio_tag == "O" or conll_tag in classes_to_ignore:
# The span has ended.
if active_conll_tag is not None:
spans.add((active_conll_tag, (span_start, span_end)))
active_conll_tag = None
# We don't care about tags we are
# told to ignore, so we do nothing.
continue
elif bio_tag == "B":
# We are entering a new span; reset indices
# and active tag to new span.
if active_conll_tag is not None:
spans.add((active_conll_tag, (span_start, span_end)))
active_conll_tag = conll_tag
span_start = index
span_end = index
elif bio_tag == "I" and conll_tag == active_conll_tag:View on GitHub (pinned to ddb1299bdd)
Solutions
- Convert IOBES to BIO first: map S-X→B-X, E-X→I-X (and keep B/I), or use an iobes-normalizing utility, before calling bio_tags_to_spans.
- If your model outputs BMES/IOBES, use the matching evaluator (e.g. evaluate_iobes) instead of the BIO-based one.
- Sanity-check the first character of each predicted tag in your decoding step.
Example fix
# before
spans = bio_tags_to_spans(pred_tags) # tags like ['S-PER','E-PER']
# after
fixed = [('B' + t[1:] if t[0] == 'S' else 'I' + t[1:] if t[0] == 'E' else t) for t in pred_tags]
spans = bio_tags_to_spans(fixed) Defensive patterns
Strategy: validation
Validate before calling
assert all(t and t[0] in 'BIO' for t in tags), 'tags must be BIO-encoded'
Type guard
def is_bio_sequence(tags):
return all(isinstance(t, str) and len(t) >= 2 and t[0] in 'BIO' and t[1] == '-' for t in tags) Prevention
- Convert IOBES/BMES predictions to BIO before span extraction.
- Pick the evaluator matching your tag scheme; add a scheme check to your eval harness.
When it happens
Trigger: Calling bio_tags_to_spans (via predict_data or evaluate_iob2) on tags in IOBES/BMES encoding (which contain S-/E-), or on malformed tags missing the BIO prefix.
Common situations: Mixing pipelines: feeding IOBES predictions from a neural model into an evaluator that expects IOB2; tags read from file without prefixes; downstream code stripping the B-/I- markers during post-processing.
Related errors
- Unrecognized label encoding {self.label_encoding}
- Unknown constraint type: {constraint_type}
- the first two dimensions of emissions and tags must match, g
- mask not supported in SpearmanCorrelation for now.
- Expect X to be 2 or 3 elements but got {repr(X)}
AI-assisted analysis of hankcs/HanLP@ddb1299bdd (2026-08-27).
Data as JSON: /api/errors/fd973ca6fe5bc5d1.
Report an issue: GitHub.