stanfordnlp/CoreNLP · error · SemgrexParseException

Cannot process a single key/value from annotation as it is…

Error message

Cannot process a single key/value from annotation  as it is not a Map

What it means

When converting node attributes to a Pattern, a single key/value pair can only be extracted from annotations whose value type is a Map (e.g. CoreDataMap-like annotations). If AnnotationLookup reports the annotation's type is not a Map, NodePattern throws SemgrexParseException because key/value matching inside that annotation is meaningless.

Solutions

  1. Use a Map-valued annotation (e.g. one whose values are Maps of attributes) for key/value matching
  2. Match the scalar annotation directly (e.g. /regex/ on the annotation) instead of key=value inside it
  3. Fix the annotation key spelling so it resolves to the intended Map-valued CoreAnnotation

Example fix

// before
[{word/foo=bar}] // word is not a Map annotation
// after
[{ner/TAG=PERSON}] // use a Map-valued annotation for key=value
Defensive patterns

Strategy: validation

Validate before calling

Class<?> clazz = AnnotationLookup.getValueType(AnnotationLookup.toCoreKey(annotation)); if (clazz == null || !Map.class.isAssignableFrom(clazz)) throw new IllegalArgumentException(annotation + " is not a Map annotation");

Type guard

boolean isMapAnnotation(String ann) { Class<?> c = AnnotationLookup.getValueType(AnnotationLookup.toCoreKey(ann)); return c != null && Map.class.isAssignableFrom(c); }

Try / catch

try { buildNodePattern(entries); } catch (SemgrexParseException e) { log.error(e.getMessage()); }

Prevention

When it happens

Trigger: Using map-style key/value matching syntax (e.g. 'key=value' inside an annotation such as 'Biennium...') against a CoreAnnotation whose getValueType is not a Map subtype (clazz==null or not Map.assignable).

Common situations: Applying map-subattribute semgrex syntax to scalar annotations like Text, Lemma, or POS; typos in the annotation key so AnnotationLookup.toCoreKey resolves to a non-Map annotation or null.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at src/edu/stanford/nlp/semgraph/semgrex/NodePattern.java:107

      }

      if (negated) {
        descString += (key + "!:" + value);
      } else {
        descString += (key + ':' + value);
      }
    }

    for (Quadruple<String, String, String, Boolean> entry : attrs.contains()) {
      String annotation = entry.first();
      String key = entry.second();
      String value = entry.third();
      boolean negated = entry.fourth();

      Class<?> clazz = AnnotationLookup.getValueType(AnnotationLookup.toCoreKey(annotation));
      boolean isMap = clazz != null && Map.class.isAssignableFrom(clazz);
      if (!isMap) {
        throw new SemgrexParseException("Cannot process a single key/value from annotation " + annotation + " as it is not a Map"); 
      }

      final Attribute attr;
      if (key.equals("__")) {
        regexPartialAttributes.add(new RegexPartialAttribute(annotation, "/.*/", value, negated));
      } else if (key.matches("/.*/")) {
        regexPartialAttributes.add(new RegexPartialAttribute(annotation, key, value, negated));
      } else {
        // Add the attributes for this key
        if (value.equals("__")) {
          attr = new Attribute(key, true, true, negated);
        } else if (value.matches("/.*/")) {
          attr = buildRegexAttribute(key, value, negated);
        } else { // raw description
          attr = new Attribute(key, value, value, negated);
        }
        partialAttributes.add(new Pair<>(annotation, attr));
      }

View on GitHub (pinned to 1b7edd19c4)