{"record":{"id":"636ea6278d1e1b46","repo":"stanfordnlp/CoreNLP","slug":"error-to-use-sutime-sentences-must-have-textanno","errorCode":null,"errorMessage":"ERROR: to use SUTime, sentences must have TextAnnotation set, or the individual tokens must have OriginalTextAnnotation or TextAnnotation set!","messagePattern":"ERROR: to use SUTime, sentences must have TextAnnotation set, or the individual tokens must have OriginalTextAnnotation or TextAnnotation set!","errorType":"exception","errorClass":"java.lang.RuntimeException","httpStatus":null,"severity":"error","filePath":"src/edu/stanford/nlp/ie/regexp/NumberSequenceClassifier.java","lineNumber":277,"sourceCode":"      Integer characterOffsetStart,\n      Integer characterOffsetEnd) {\n\n    //\n    // Recover the sentence text:\n    // a) try to get it from TextAnnotation\n    // b) if not present, build it from the OriginalTextAnnotation of each token\n    // c) if not present, build it from the TextAnnotation of each token\n    //\n    boolean adjustCharacterOffsets = false;\n    // try to recover the text from the original tokens\n    String text = buildText(tokens, CoreAnnotations.OriginalTextAnnotation.class);\n    if(text == null){\n      text = buildText(tokens, CoreAnnotations.TextAnnotation.class);\n      // character offset will point to the original tokens\n      //   so we need to align them to the text built from normalized tokens\n      adjustCharacterOffsets = true;\n      if(text == null){\n        throw new RuntimeException(\"ERROR: to use SUTime, sentences must have TextAnnotation set, or the individual tokens must have OriginalTextAnnotation or TextAnnotation set!\");\n      }\n    }\n\n    // make sure token character offsets are aligned with text\n    List<CoreLabel> tokenSequence = copyTokens(tokens, adjustCharacterOffsets, false);\n\n    Annotation newSentence = new Annotation(text);\n    newSentence.set(CoreAnnotations.TokensAnnotation.class, tokenSequence);\n    if (! adjustCharacterOffsets &&\n        characterOffsetStart != null &&\n        characterOffsetEnd != null){\n      newSentence.set(CoreAnnotations.CharacterOffsetBeginAnnotation.class, characterOffsetStart);\n      newSentence.set(CoreAnnotations.CharacterOffsetEndAnnotation.class, characterOffsetEnd);\n    } else {\n      int tokenCharStart = tokenSequence.get(0).get(CoreAnnotations.CharacterOffsetBeginAnnotation.class);\n      int tokenCharEnd = tokenSequence.get(tokenSequence.size() - 1).get(CoreAnnotations.CharacterOffsetEndAnnotation.class);\n      newSentence.set(CoreAnnotations.CharacterOffsetBeginAnnotation.class, tokenCharStart);\n      newSentence.set(CoreAnnotations.CharacterOffsetEndAnnotation.class, tokenCharEnd);","sourceCodeStart":259,"sourceCodeEnd":295,"githubUrl":"https://github.com/stanfordnlp/CoreNLP/blob/1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a/src/edu/stanford/nlp/ie/regexp/NumberSequenceClassifier.java#L259-L295","documentation":"NumberSequenceClassifier.buildSentenceFromTokens constructs a synthetic sentence for SUTime from a token list; it needs the sentence's TextAnnotation, or per-token OriginalTextAnnotation/TextAnnotation, to rebuild the text. When neither is present, text is null and this RuntimeException is thrown.","triggerScenarios":"Calling SUTime/NumberSequenceClassifier classification on CoreMaps that were created programmatically without TextAnnotation on the sentence and without TextAnnotation or OriginalTextAnnotation on each token — e.g. custom annotation code that sets only word()/value().","commonSituations":"Piping tokens from a custom reader/annotator into SUTime, calling SUTime directly on tokens built by hand, or an annotator order where tokens lost their text fields (e.g. after normalization that only sets normalized fields).","solutions":["Ensure each token has TextAnnotation (coremap.get(CoreAnnotations.TextAnnotation.class)) set before invoking the classifier.","Run the tokenize/ssa annotators upstream so text fields are populated rather than building CoreMaps manually.","If you normalize tokens, also set OriginalTextAnnotation on each token.","Set TextAnnotation on the containing sentence CoreMap."],"exampleFix":"// before\nCoreLabel tok = new CoreLabel();\ntok.set(CoreAnnotations.ValueAnnotation.class, \"five\");\n// after\nCoreLabel tok = new CoreLabel();\ntok.set(CoreAnnotations.TextAnnotation.class, \"five\");","handlingStrategy":"type-guard","validationCode":"boolean sutimeReady(List<CoreLabel> tokens) {\n  return tokens.stream().allMatch(t ->\n    t.get(CoreAnnotations.TextAnnotation.class) != null ||\n    t.get(CoreAnnotations.OriginalTextAnnotation.class) != null);\n}","typeGuard":"static boolean hasTokenText(CoreLabel t) {\n  return t.get(CoreAnnotations.TextAnnotation.class) != null\n      || t.get(CoreAnnotations.OriginalTextAnnotation.class) != null;\n}","tryCatchPattern":"try {\n  sutime.classify(tokens);\n} catch (RuntimeException e) {\n  if (e.getMessage().contains(\"TextAnnotation\")) {\n    log.warning(\"Tokens lack text annotations; run tokenizer/ssa first\");\n  }\n}","preventionTips":["Always run tokenize (and ssa for numbers) before SUTime.","Never build CoreLabels with only value()/word(); set TextAnnotation.","In tests, use a full pipeline to generate tokens."],"tags":["sutime","annotations","preconditions","coremap"],"backgroundTag":"missing-required-argument","analyzedSha":"1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a","analyzedAt":"2026-09-10T02:24:07.274Z","contentChangedAt":"2026-09-10T02:24:07.274Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}