Common YAML Map Errors (old)

From Team 449 Wiki

Numerous errors can come up when testing a robot map, but often the error messages are difficult to interpret. This page explains some of the most common errors you may encounter.

Seeing error messages

Just seeing the error messages can be difficult, as the FRC Driver Station console is constantly scrolling, so your message may go away before you have a chance to read it. Taking a quick screenshot can work, although the best method is to install the FRC IntelliJ Plugin and use the console it gives you in the "FRC" tab at the bottom. Press play to get it running, then press pause as soon as the error appears.

Valid map

Below is a map with valid YAML. The entire source code can be found here.

---
classname: "Physics"
teacher:
  '@id': davis
  name: "Dr. John Davis"
  salary: 1000000
students:
  - students.Student:
      '@id': susan
      grade: 12
      name: "Susan"
  - students.LiveInStudent:
      '@id': billy
      grade: 10
      name: "Billy"
      gpa: 3.67
      buildingNum: 5
      hasMealPlan: true
valedictorian:
  susan

Now we can edit this map and see what errors we get.

Simple typo

The most basic error you'll get is just from simply spelling incorrectly a class name or its path. For example, if we change "students.Student" to "students.Stupent", we'll get the following error:

Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve type id 'students.Stupent' into a subtype of [simple type, class students.Student]: no such class found
 at [Source: (StringReader); line: 8, column: 3] (through reference chain: Class["students"]->java.util.ArrayList[0])
	at com.fasterxml.jackson.databind.exc.InvalidTypeIdException.from(InvalidTypeIdException.java:43)
	at com.fasterxml.jackson.databind.DeserializationContext.unknownTypeIdException(DeserializationContext.java:1574)
        ...

The stack trace is even longer, but we only care abound the first line or two of the error message. The parser says it expected a students.Student and instead got something it couldn't resolve to such a class; specifically, the class "students.Stupent" doesn't exist.

For a file this small, the typo is fairly easy to find in the map. But for bigger files, here are a couple general tips:

  1. Ctrl-F the map for the typo, i.e. "students.Stupent".
  2. The first line of the stack trace tells you exactly where the error came from. Class["students"]->java.util.ArrayList[0] indicates that the error appears in the element at index zero in the ArrayList called "students" which is a property of the Class object.

Not a subtype

Alternatively, if you change "students.Student" to a class that does exist but isn't a Student, e.g. "Teacher" you'll get the following error:

Caused by: java.lang.IllegalArgumentException: Class Teacher not subtype of [simple type, class students.Student]

Improper indentation

Indentation matters in YAML. If we untab susan in the valedictorian, we'll get the following error:

Exception in thread "main" while scanning a simple key
 in 'reader', line 21, column 3:
      susan
      ^
could not find expected ':'
 in 'reader', line 21, column 8:
    susan
         ^

	at org.yaml.snakeyaml.scanner.ScannerImpl.removePossibleSimpleKey(ScannerImpl.java:514)
	at org.yaml.snakeyaml.scanner.ScannerImpl.fetchStreamEnd(ScannerImpl.java:588)

Most of this can be ignored, as the first two lines tell alone us that a syntax error occurred on line 21 in the map.

To avoid errors like this, keep consistent indentation standards throughout the map. Follow conventions our team uses, e.g. only use two spaces to tab instead of four.

Missing required property

All properties marked in the constructor as @JsonProperty(required = true) must be provided in the map. If you omit one, e.g. the teacher's name, you'll get the following error:

Exception in thread "main" com.fasterxml.jackson.databind.exc.MismatchedInputException: Missing required creator property 'name' (index 0)
 at [Source: (StringReader); line: 6, column: 1] (through reference chain: Class["teacher"])

Non-existent property

If you provide a property that doesn't actually exist in the constructor of an object, you'll also get an error. Here's what you get when you add degree: "PhD" to the teacher:

Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "degree" (class Teacher), not marked as ignorable (3 known properties: "salary", "name", "@id"])
 at [Source: (StringReader); line: 7, column: 16] (through reference chain: Class["teacher"]->Teacher["degree"])

The only properties it knows are salary, name, and id, and "degree" is not one of those.

Giving two objects the same ID

Changing Susan's ID to davis produces the following error:

Caused by: java.lang.IllegalStateException: Already had POJO for id (java.lang.String) [[ObjectId: key=davis, type=com.fasterxml.jackson.annotation.ObjectIdGenerators$StringIdGenerator, scope=NONE]]

All you get to find the error is the ID in conflict, so to find the error you'd have to Ctrl-F for '@id': davis to see where new objects are being created with that ID.

Referencing an object that hasn't been made yet

Let's try moving the valedictorian object above the student list:

---
classname: "Physics"
teacher:
  '@id': davis
  name: "Dr. John Davis"
  salary: 1000000
valedictorian:
  susan
students:
  - students.Student:
      '@id': susan
      grade: 12
      name: "Susan"
  - students.LiveInStudent:
      '@id': billy
      grade: 10
      name: "Billy"
      gpa: 3.67
      buildingNum: 5
      hasMealPlan: true

This is going to give the following error:

Exception in thread "main" com.fasterxml.jackson.databind.deser.UnresolvedForwardReference: Could not resolve Object Id [susan] (for [simple type, class students.Student]).
 at [Source: (StringReader); line: 8, column: 28] (through reference chain: Class["valedictorian"])

All objects must be defined before they can be referenced by their ID; YAML can't read forward to look for matching IDs. You'd get the same error if you tried referencing an ID that doesn't exist at all.

Giving class name when unnecessary

Notice how to make a student, you must provide the class name, including the path to that class. This is not necessary, however, for the teacher. This is because a list of students can contain both Students and LiveInStudents. The parser doesn't know which type of object you'll want to construct, so you need to say what it is explicitly. On the other hand, there is only one Teacher class so it would be redundant to do the following:

---
classname: "Physics"
teacher:
  Teacher:
    '@id': davis
    name: "Dr. John Davis"
    salary: 1000000
students:
  - students.Student:
      '@id': susan
      grade: 12
      name: "Susan"
  - students.LiveInStudent:
      '@id': billy
      grade: 10
      name: "Billy"
      gpa: 3.67
      buildingNum: 5
      hasMealPlan: true
valedictorian:
  susan

Not only is it redundant, but it will produce an error, as the parser is expecting to see the teacher's properties, not a class name. This is the error you get:

Exception in thread "main" com.fasterxml.jackson.databind.exc.MismatchedInputException: Missing required creator property 'name' (index 0)
 at [Source: (StringReader); line: 8, column: 1] (through reference chain: Class["teacher"])

Unfortunately, this error message can be confusing if you don't know what the real problem is. "What do you mean I'm missing a name, it's right there!" Well, not exactly...

The actual thing that determines if you need to provide the class name or not is whether the object you're constructing has the following line above the class declaration:

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.WRAPPER_OBJECT, property = "@class")

This annotation basically allows you to use subclasses in the map. If it's there, you need to provide the class name/path. If it's not, do not provide it.

(Similarly, provide an '@id' if and only if the object contains @JsonIdentityInfo(generator = ObjectIdGenerators.StringIdGenerator.class) above the class declaration.)

Omitting class name when necessary

As implied, any object with the JsonTypeInfo.Id.CLASS annotation must have its class given explicitly. If we neglect to, e.g.:

---
classname: "Physics"
teacher:
  '@id': davis
  name: "Dr. John Davis"
  salary: 1000000
students:
  - '@id': susan
    grade: 12
    name: "Susan"
  - '@id': billy
    grade: 10
    name: "Billy"
    gpa: 3.67
    buildingNum: 5
    hasMealPlan: true
valedictorian:
  susan

We'll get the following error:

Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve type id '@id' into a subtype of [simple type, class students.Student]: no such class found
 at [Source: (StringReader); line: 8, column: 3] (through reference chain: Class["students"]->java.util.ArrayList[0])

Again, this error doesn't point to the exact problem, but you can see the parser was expecting a class name and got '@id' instead.

Reusing commands

This is a bit specific, but be careful when creating command objects and referencing them later. For example, let's say you have multiple times in your code when you want to delay for a second as part of a command sequence. You can't create one command with ID "delay1sec" and use it again later in the map. You'll have to construct a new command with the same properties, but a different ID, each time you want to delay. (Using merge syntax, discussed in maps, would be a good idea for this.) This has to do with the fact that it could cause issues with the WPILib Scheduler to have a command be used by two different commands.