stanfordnlp/CoreNLP · warning

: Unknown field: cannot find suitable annotation class

Error message

${name}: Unknown field: ${field} cannot find suitable annotation class

What it means

TokensRegexNERAnnotator lets rules map fields to CoreNLP annotation classes. When a field name in a rule header cannot be resolved to any Annotation key class (via EnvLookup), the annotator logs this warning and simply omits that field. Rules still load, but the intended field will never be populated.

Solutions

  1. Check the field name spelling in the rules file header against CoreNLP's CoreAnnotations classes
  2. Use the Classname: suffix (e.g. myfield:edu.stanford.nlp.ling.CoreAnnotations$NormalizedNamedEntityTag) so the class can be found
  3. Remove fields you don't actually need from the rule header
  4. Verify the CoreNLP version supports the field you reference

Example fix

// before (rules file header)
tokens = { word: /Barack/ }
PosTag: NN
// after
tokens = { word: /Barack/ }
PartOfSpeech: NN
Defensive patterns

Strategy: validation

Validate before calling

Set<String> known = Set.of("text","word","lemma","pos","ner","normalized","partOfSpeech");
for (String field : headerFields) {
  if (!known.contains(field) && !field.contains(":"))
    throw new IllegalArgumentException("Unknown rule field: " + field);
}

Prevention

When it happens

Trigger: Defining a TokensRegex rules file with a header field whose name (or explicit classname after ':') does not correspond to any CoreNLP annotation class, e.g. a typo like 'PartOfSpeach' or a custom name without a registered class.

Common situations: Typo'd field names in tokensregex rules; custom annotation keys used in rules without registering/looking up the class name; copy-pasting rule headers between CoreNLP versions where a field was renamed.

Related errors


AI-assisted analysis of stanfordnlp/CoreNLP@1b7edd19c4 (2026-09-10). Data as JSON: /api/errors/b0aa0e9f709aa21f. Report an issue: GitHub.

Appendix: source

Thrown at src/edu/stanford/nlp/pipeline/TokensRegexNERAnnotator.java:292

    } else {
      headerFields = COMMA_DELIMITERS_PATTERN.split(headerProp);
      // Take header fields and remove known headers to get annotation field names
      List<String> fieldNames = new ArrayList<>();
      List<Class> fieldClasses = new ArrayList<>();
      for (String field : headerFields) {
        if ( ! predefinedHeaderFields.contains(field)) {
          Class fieldClass = EnvLookup.lookupAnnotationKeyWithClassname(null, field);
          if (fieldClass == null) {
            // check our properties
            String classname = properties.getProperty(prefix + "mapping.field." + field);
            fieldClass = EnvLookup.lookupAnnotationKeyWithClassname(null, classname);
          }
          if (fieldClass != null) {
            fieldNames.add(field);
            fieldClasses.add(fieldClass);
          } else {
            logger.warn(name + ": Unknown field: " + field + " cannot find suitable annotation class");
          }
        }
      }
      
      annotationFieldnames = new String[fieldNames.size()];
      fieldNames.toArray(annotationFieldnames);
      annotationFields = fieldClasses;
    }

    String noDefaultOverwriteLabelsProp = properties.getProperty(prefix + "noDefaultOverwriteLabels", "CITY");
    this.noDefaultOverwriteLabels = Collections.unmodifiableSet(CollectionUtils.asSet(COMMA_DELIMITERS_PATTERN.split(noDefaultOverwriteLabelsProp)));
    this.ignoreCase = PropertiesUtils.getBool(properties, prefix + "ignorecase", false);
    this.verbose = PropertiesUtils.getBool(properties, prefix + "verbose", false);

    if ( ! StringUtils.isNullOrEmpty(validPosRegex)) {
      validPosPattern = Pattern.compile(validPosRegex);
    } else {
      validPosPattern = null;

View on GitHub (pinned to 1b7edd19c4)