diff --git a/src/main/jastadd/Analysis.jrag b/src/main/jastadd/Analysis.jrag
index 6c8755e77db354ed36900f3439cd6fd8c5e6f2f5..228a3479df5be9d24998479bc3b48bd1626775aa 100644
--- a/src/main/jastadd/Analysis.jrag
+++ b/src/main/jastadd/Analysis.jrag
@@ -1,23 +1,27 @@
 aspect Analysis {
-  // --- isPrimitiveType ---
-  syn boolean TokenComponent.isPrimitiveType() = getJavaTypeUse().isPrimitiveType();
-  syn boolean JavaTypeUse.isPrimitiveType() = false;
-  eq SimpleJavaTypeUse.isPrimitiveType() {
-    switch(getName()) {
-      case "int":
-      case "short":
-      case "long":
-      case "float":
-      case "double":
-      case "char":
-      case "byte": return true;
-      default: return false;
+  // --- lookupTokenUpdateDefinition ---
+  inh TokenUpdateDefinition TokenUpdateDefinition.lookupTokenUpdateDefinition(TokenComponent token);
+  eq Ros2Rag.getUpdateDefinition().lookupTokenUpdateDefinition(TokenComponent token) {
+    for (UpdateDefinition def : getUpdateDefinitionList()) {
+      if (def.isTokenUpdateDefinition() && def.asTokenUpdateDefinition().getToken().equals(token)) {
+        return def.asTokenUpdateDefinition();
+      }
     }
+    return null;
   }
 
-  // --- prettyPrint ---
-  syn String MappingDefinitionType.prettyPrint();
-  eq JavaMappingDefinitionType.prettyPrint() = getType().getName();
-  eq JavaArrayMappingDefinitionType.prettyPrint() = getType().getName() + "[]";
+  // --- lookupDependencyDefinition ---
+  inh DependencyDefinition DependencyDefinition.lookupDependencyDefinition(TypeDecl source, String id);
+  eq Ros2Rag.getDependencyDefinition().lookupDependencyDefinition(TypeDecl source, String id) {
+    for (DependencyDefinition def : getDependencyDefinitionList()) {
+      if (def.getID().equals(id) && def.getSource().containingTypeDecl().equals(source)) {
+        return def;
+      }
+    }
+    return null;
+  }
 
+  // --- isAlreadyDefined ---
+  syn boolean TokenUpdateDefinition.isAlreadyDefined() = lookupTokenUpdateDefinition(getToken()) != this;
+  syn boolean DependencyDefinition.isAlreadyDefined() = lookupDependencyDefinition(getSource().containingTypeDecl(), getID()) != this;
 }
diff --git a/src/main/jastadd/Errors.jrag b/src/main/jastadd/Errors.jrag
index 7fb6b00b626a04b0d0c9eb3036242d728c64e050..ef223a4081e169273555140a35a9f8b47876109d 100644
--- a/src/main/jastadd/Errors.jrag
+++ b/src/main/jastadd/Errors.jrag
@@ -7,15 +7,59 @@ aspect Errors {
     [new TreeSet<ErrorMessage>()]
     root Ros2Rag;
 
-//  TypeUse contributes error("Type '" + getID() + "' not found")
-//    when decl() == null && !isToken()
-//    to Program.errors();
+    ReadFromMqttDefinition contributes error("Read definition already defined for " + getToken().getName())
+      when isAlreadyDefined()
+      to Ros2Rag.errors();
+
+    ReadFromMqttDefinition contributes error("Reading target token must not be an NTA token!")
+      when getToken().getNTA()
+      to Ros2Rag.errors();
+
+    // if first mapping is null, then suitableDefaultMapping() == null
+    ReadFromMqttDefinition contributes error("No suitable default mapping found for type " +
+      ((getMappingList().isEmpty())
+        ? getToken().getJavaTypeUse().prettyPrint()
+        : getMappingList().get(0).getFromType().prettyPrint()))
+      when effectiveMappings().get(0) == null
+      to Ros2Rag.errors();
 
-    UpdateDefinition contributes error("")
-      when true
+    ReadFromMqttDefinition contributes error("to-type of last mapping must be type of the Token!")
+      when getToken().getJavaTypeUse().prettyPrint().equals(
+          effectiveMappings().get(effectiveMappings().size() - 1))
+      to Ros2Rag.errors();
+
+    WriteToMqttDefinition contributes error("Writing target token must be an NTA token!")
+      when !getToken().getNTA()
+      to Ros2Rag.errors();
+
+    WriteToMqttDefinition contributes error("Write definition already defined for " + getToken().getName())
+      when isAlreadyDefined()
+      to Ros2Rag.errors();
+
+    DependencyDefinition contributes error("Dependency definition already defined for " + getSource().containingTypeDecl().getName() + " with name " + getID())
+      when isAlreadyDefined()
+      to Ros2Rag.errors();
+
+    DependencyDefinition contributes error("The name of a dependency definition must not be equal to a list-node on the source")
+      when isAlreadyDefinedAsList()
+      to Ros2Rag.errors();
+
+    DependencyDefinition contributes error("There must be a write update definition targeting " + getSource().parentTypeypeAndName() + " for dependency definition " + getID())
+      when targetUpdateDefinition() == null
       to Ros2Rag.errors();
 }
 
+aspect ErrorHelpers {
+  syn boolean DependencyDefinition.isAlreadyDefinedAsList() {
+    for (Component comp : getSource().containingTypeDecl().getComponentList()) {
+      if (comp.isListComponent() && comp.getName().equals(this.getID())) {
+        return true;
+      }
+    }
+    return false;
+  }
+  syn String TokenComponent.parentTypeypeAndName() = containingTypeDecl().getName() + "." + getName();
+}
 
 aspect ErrorMessage {
   public class ErrorMessage implements Comparable<ErrorMessage> {
@@ -27,7 +71,7 @@ aspect ErrorMessage {
 
     public ErrorMessage(ASTNode node, String message) {
       this.node = node;
-      this.filename = node.containedFile().getFileName();
+      this.filename = node.containedFileName();
       this.line = node.getStartLine();
       this.col = node.getStartColumn();
       this.message = message;
diff --git a/src/main/jastadd/Navigation.jrag b/src/main/jastadd/Navigation.jrag
index 49b86d0e08ba75d817cf2e53255f8ae0c2ae9edf..f56d99825c376248ce8f9a2dae1388ed3898ea64 100644
--- a/src/main/jastadd/Navigation.jrag
+++ b/src/main/jastadd/Navigation.jrag
@@ -19,6 +19,28 @@ aspect Navigation {
   syn TypeComponent Component.asTypeComponent() = null;
   eq TypeComponent.asTypeComponent() = this;
 
+  // --- isListComponent (should be in preprocessor) ---
+  syn boolean Component.isListComponent() = false;
+  eq ListComponent.isListComponent() = true;
+
+  // --- asListComponent (should be in preprocessor) ---
+  syn ListComponent Component.asListComponent() = null;
+  eq ListComponent.asListComponent() = this;
+
+  // --- containedFileName (should replace containedFile in preprocessor) ---
+  inh String ASTNode.containedFileName();
+  eq GrammarFile.getChild().containedFileName() = getFileName();
+  eq Ros2Rag.getChild().containedFileName() = getFileName();
+  eq Program.getChild().containedFileName() = null;
+
+  // --- isTokenUpdateDefinition ---
+  syn boolean UpdateDefinition.isTokenUpdateDefinition() = false;
+  eq TokenUpdateDefinition.isTokenUpdateDefinition() = true;
+
+  // --- asTokenUpdateDefinition ---
+  syn TokenUpdateDefinition UpdateDefinition.asTokenUpdateDefinition() = null;
+  eq TokenUpdateDefinition.asTokenUpdateDefinition() = this;
+
   // --- isWriteToMqttDefinition ---
   syn boolean UpdateDefinition.isWriteToMqttDefinition() = false;
   eq WriteToMqttDefinition.isWriteToMqttDefinition() = true;
diff --git a/src/main/jastadd/Ros2Rag.relast b/src/main/jastadd/Ros2Rag.relast
index 1008207a6ceb854a1937e7a2a16ef6e22cbccc03..a5499702f44facd5b649a811a958b890d4565d0a 100644
--- a/src/main/jastadd/Ros2Rag.relast
+++ b/src/main/jastadd/Ros2Rag.relast
@@ -1,4 +1,4 @@
-Ros2Rag ::= UpdateDefinition* DependencyDefinition* MappingDefinition* Program;
+Ros2Rag ::= UpdateDefinition* DependencyDefinition* MappingDefinition* Program <FileName> ;
 
 abstract UpdateDefinition ::= <AlwaysApply:boolean> ;
 
diff --git a/src/main/jastadd/backend/Generation.jadd b/src/main/jastadd/backend/Generation.jadd
index 7e1f988c2150a3970e53a6e36f7e22f1bd3ebc96..e698e405ee6d392d2405b15fe0869432b9b18a59 100644
--- a/src/main/jastadd/backend/Generation.jadd
+++ b/src/main/jastadd/backend/Generation.jadd
@@ -8,6 +8,17 @@ aspect GenerationUtils {
     }
     return s.toString();
   }
+
+  // --- prettyPrint ---
+  syn String MappingDefinitionType.prettyPrint();
+  eq JavaMappingDefinitionType.prettyPrint() = getType().getName();
+  eq JavaArrayMappingDefinitionType.prettyPrint() = getType().getName() + "[]";
+
+  syn String JavaTypeUse.prettyPrint() {
+    StringBuilder sb = new StringBuilder();
+    generateAbstractGrammar(sb);
+    return sb.toString();
+  }
 }
 
 aspect AspectGeneration {
@@ -248,9 +259,8 @@ aspect AspectGeneration {
     String parentTypeName = containingTypeDecl().getName();
     // virtual setter
     sb.append(ind(1)).append("public ").append(parentTypeName).append(" ")
-      .append(parentTypeName).append(".set").append(getName()).append("(");
-    getJavaTypeUse().generateAbstractGrammar(sb);
-    sb.append(" value) {\n");
+      .append(parentTypeName).append(".set").append(getName()).append("(")
+      .append(getJavaTypeUse().prettyPrint()).append(" value) {\n");
     sb.append(ind(2)).append("set").append(internalName()).append("(value);\n");
 
     for (DependencyDefinition dependencyDefinition : getDependencySourceDefinitionList()) {
@@ -270,9 +280,8 @@ aspect AspectGeneration {
     sb.append(ind(1)).append("}\n\n");
 
     // virtual getter
-    sb.append(ind(1)).append("public ");
-    getJavaTypeUse().generateAbstractGrammar(sb);
-    sb.append(" ").append(parentTypeName).append(".get").append(getName()).append("() {\n");
+    sb.append(ind(1)).append("public ").append(getJavaTypeUse().prettyPrint())
+      .append(" ").append(parentTypeName).append(".get").append(getName()).append("() {\n");
     sb.append(ind(2)).append("return get").append(internalName()).append("();\n");
     sb.append(ind(1)).append("}\n\n");
   }
diff --git a/src/main/jastadd/backend/Mappings.jrag b/src/main/jastadd/backend/Mappings.jrag
index 4bfe070a81b49e63996ba8f9a32a43eb13af6d1f..7add42fa7e3d3f7c71cb35b5a34c8c5d05b83628 100644
--- a/src/main/jastadd/backend/Mappings.jrag
+++ b/src/main/jastadd/backend/Mappings.jrag
@@ -136,6 +136,22 @@ aspect Mappings {
     return result;
   }
 
+  // --- isPrimitiveType ---
+  syn boolean TokenComponent.isPrimitiveType() = getJavaTypeUse().isPrimitiveType();
+  syn boolean JavaTypeUse.isPrimitiveType() = false;
+  eq SimpleJavaTypeUse.isPrimitiveType() {
+    switch(getName()) {
+      case "int":
+      case "short":
+      case "long":
+      case "float":
+      case "double":
+      case "char":
+      case "byte": return true;
+      default: return false;
+    }
+  }
+
   // --- suitableDefaultMapping ---
   syn DefaultMappingDefinition UpdateDefinition.suitableDefaultMapping();
   eq ReadFromMqttDefinition.suitableDefaultMapping() {
diff --git a/src/main/java/org/jastadd/ros2rag/compiler/Compiler.java b/src/main/java/org/jastadd/ros2rag/compiler/Compiler.java
index ad4298dbd873ca42b66d85793685b78c91f01e4d..ee575b9495f53eca9925c6828ba96225734fe31a 100644
--- a/src/main/java/org/jastadd/ros2rag/compiler/Compiler.java
+++ b/src/main/java/org/jastadd/ros2rag/compiler/Compiler.java
@@ -85,6 +85,14 @@ public class Compiler {
     }
     Ros2Rag ros2Rag = parseProgram(optionInputGrammar.getValue(), optionInputRos2Rag.getValue());
 
+    if (!ros2Rag.errors().isEmpty()) {
+      System.err.println("Errors:");
+      for (ErrorMessage e : ros2Rag.errors()) {
+        System.err.println(e);
+      }
+      System.exit(1);
+    }
+
     printMessage("Writing output files");
     // copy MqttUpdater into outputDir
     final String mqttUpdaterFileName = "MqttUpdater.jadd";
@@ -169,6 +177,7 @@ public class Compiler {
       }
       program.addGrammarFile(inputGrammar);
       inputGrammar.treeResolveAll();
+      inputGrammar.setFileName(inputGrammarFileName);
     } catch (IOException | Parser.Exception e) {
       throw new CompilerException("Could not parse grammar file " + inputGrammarFileName, e);
     }
@@ -178,6 +187,7 @@ public class Compiler {
       Ros2RagParser parser = new Ros2RagParser();
       ros2Rag = (Ros2Rag) parser.parse(scanner, Ros2RagParser.AltGoals.ros2rag);
       ros2Rag.setProgram(program);
+      ros2Rag.setFileName(inputRos2RagFileName);
     } catch (IOException | Parser.Exception e) {
       throw new CompilerException("Could not parse ros2rag file " + inputRos2RagFileName, e);
     }