stanfordnlp/CoreNLP · error · RuntimeException
TIMEX3 should only contain text
Error message
TIMEX3 should only contain text ${child} What it means
When converting GUTime's XML output into CoreMaps, toTimexCoreMaps expects every TIMEX3 element to wrap exactly one child node (the text). If a TIMEX3 element contains zero or more than one child node (e.g. nested markup or split text nodes), the annotator throws this RuntimeException because it cannot represent it as a single text timex.
Solutions
- Log the offending TIMEX3 element (it is included in the message) and inspect what extra child nodes it contains
- Strip/escape inline markup from the input text before annotation so GUTime emits plain-text TIMEX3 elements
- Preprocess the GUTime XML output to merge/split non-conforming TIMEX3 elements before calling toTimexCoreMaps
- Align the GUTime version with the one CoreNLP was built against
Example fix
// before
String text = docHtml; // contains <b>Feb 3</b> inline markup
guTimeAnnotator.annotate(new Annotation(text));
// after
String text = docHtml.replaceAll("<[^>]+>", ""); // plain text only
guTimeAnnotator.annotate(new Annotation(text)); Defensive patterns
Strategy: validation
Validate before calling
// Validate TIMEX3 elements in GUTime output before conversion
NodeList timexes = outputXML.getElementsByTagName("TIMEX3");
for (int i = 0; i < timexes.getLength(); i++) {
Element e = (Element) timexes.item(i);
if (e.getChildNodes().getLength() != 1)
throw new IllegalStateException("Non-conforming TIMEX3 at index " + i + ": " + e.getTextContent());
} Try / catch
try {
guTimeAnnotator.annotate(annotation);
} catch (RuntimeException e) {
if (e.getMessage() != null && e.getMessage().startsWith("TIMEX3 should only contain text")) {
logger.warning("Skipping malformed TIMEX3: " + e.getMessage());
} else throw e;
} Prevention
- Pass plain text (markup stripped) to the annotator so TIMEX3 elements contain a single text node
- Pin a GUTime version compatible with CoreNLP's output parser
- Log the full element from the message to spot systematic input issues
When it happens
Trigger: GUTime emits TIMEX3 elements containing nested elements or multiple text nodes — typically due to unusual input markup, HTML fragments passed through to GUTime, or an unexpected GUTime version producing a different XML schema than expected.
Common situations: Annotating documents that already contain inline markup (XML/HTML) that survives into GUTime output; using a newer/older GUTime release whose TIMEX3 serialization differs from what the CoreNLP parser assumes.
Related errors
- unexpected element
- unexpected content
- Bad number put into wordToNumber. Word is: \"" + input +…
- Error in wordToNumber function.
- Bad number put into wordToNumber. Word is: \"" + curPart +…
AI-assisted analysis of stanfordnlp/CoreNLP@1b7edd19c4 (2026-09-10).
Data as JSON: /api/errors/408e3af7f0e44996.
Report an issue: GitHub.
Appendix: source
Thrown at src/edu/stanford/nlp/time/GUTimeAnnotator.java:280
for (int i = 0; i < docNodes.getLength(); i++) {
Node n = docNodes.item(i);
if ("text".equals(n.getNodeName())) {
textElem = (Element) n;
break;
}
}
NodeList textNodes = textElem.getChildNodes();
for (int i = 0; i < textNodes.getLength(); i++) {
Node content = textNodes.item(i);
if (content instanceof Text) {
Text text = (Text)content;
offset += text.getWholeText().length();
} else if (content instanceof Element) {
Element child = (Element)content;
if (child.getNodeName().equals("TIMEX3")) {
Timex timex = new Timex(child);
if (child.getChildNodes().getLength() != 1) {
throw new RuntimeException("TIMEX3 should only contain text " + child);
}
String timexText = child.getTextContent();
CoreMap timexMap = new ArrayCoreMap();
//(timex)
timexMap.set(TimeAnnotations.TimexAnnotation.class, timex);
//(text)
timexMap.set(CoreAnnotations.TextAnnotation.class, timexText);
//(characters)
int charBegin = offset;
timexMap.set(CoreAnnotations.CharacterOffsetBeginAnnotation.class, charBegin);
offset += timexText.length();
int charEnd = offset;
timexMap.set(CoreAnnotations.CharacterOffsetEndAnnotation.class, charEnd);
//(tokens)
if(haveTokenOffsets){
Integer tokBegin = beginMap.get(charBegin);
int searchStep = 1; //if no exact match, search around the character offset
while(tokBegin == null){View on GitHub (pinned to 1b7edd19c4)