diff --git a/src/main/java/mi/hdm/controllers/MealPlanController.java b/src/main/java/mi/hdm/controllers/MealPlanController.java
index eb30903d6fbb52c244dda4143c5afc5dc7850860..e600016e56858d7de77c20d2b1d2b0b010737a6b 100644
--- a/src/main/java/mi/hdm/controllers/MealPlanController.java
+++ b/src/main/java/mi/hdm/controllers/MealPlanController.java
@@ -11,6 +11,7 @@ import javafx.scene.layout.*;
 import javafx.scene.text.Font;
 import javafx.scene.text.FontWeight;
 import mi.hdm.components.IngredientSearchResultLabel;
+import mi.hdm.exceptions.MissingContentException;
 import mi.hdm.mealPlan.MealPlan;
 import mi.hdm.recipes.IngredientManager;
 import mi.hdm.recipes.Recipe;
@@ -77,40 +78,53 @@ public class MealPlanController extends BaseController {
         for (int j = 0; j < 7; j++) {
             final int J = j;
             mealPlan.getRecipeCodeForDay(LocalDate.now().plusDays(J)).ifPresentOrElse(code -> {
-                Recipe r = recipeManager.getRecipe(code).get();
-                VBox displayRecipeVBox = new VBox();
-                ImageView recipeImage = new ImageView(new Image(r.getImageURL().toString()));
-
-                HBox recipeHBox = new HBox();
-                Label name = new Label(r.getName());
-                name.setFont(font);
-                name.setStyle("-fx-padding: 0 50 10 10;");
-                name.setCursor(Cursor.HAND);
-                name.setTooltip(new Tooltip("Click to display this recipe"));
-                name.setOnMouseClicked(e ->
-                        changeScene(View.RECIPE_VIEW, r)
-                );
+                try {
+                    //if this day has code, fetch the recipe and display it in the grid
+                    Recipe r = recipeManager.getRecipe(code).orElseThrow(() -> new MissingContentException(code, Recipe.class));
+                    VBox displayRecipeVBox = new VBox();
+                    ImageView recipeImage = new ImageView(new Image(r.getImageURL().toString()));
+
+                    HBox recipeHBox = new HBox();
+                    Label name = new Label(r.getName());
+                    name.setFont(font);
+                    name.setStyle("-fx-padding: 0 50 10 10;");
+                    name.setCursor(Cursor.HAND);
+                    name.setTooltip(new Tooltip("Click to display this recipe"));
+                    name.setOnMouseClicked(e ->
+                            changeScene(View.RECIPE_VIEW, r)
+                    );
 
-                Button removeRecipeButton = new Button();
-                removeRecipeButton.setStyle("-fx-background-color: dedede;" +
-                        "-fx-background-radius: 5;");
-                ImageView xIconImage = new ImageView(String.valueOf(Recipe.class.getResource("/images/Tasty_Pages_X_Icon.png")));
-                xIconImage.setPreserveRatio(true);
-                xIconImage.setFitHeight(20);
-                xIconImage.setFitWidth(20);
-                removeRecipeButton.setGraphic(xIconImage);
-                removeRecipeButton.setOnAction(e -> {
-                    mealPlan.clear(LocalDate.now().plusDays(J));
+                    Button removeRecipeButton = new Button();
+                    removeRecipeButton.setStyle("-fx-background-color: #dedede;" +
+                            "-fx-background-radius: 5;");
+                    ImageView xIconImage = new ImageView(String.valueOf(Recipe.class.getResource("/images/Tasty_Pages_X_Icon.png")));
+                    xIconImage.setPreserveRatio(true);
+                    xIconImage.setFitHeight(20);
+                    xIconImage.setFitWidth(20);
+                    removeRecipeButton.setGraphic(xIconImage);
+                    removeRecipeButton.setOnAction(e -> {
+                        mealPlan.clear(LocalDate.now().plusDays(J));
+                        render();
+                    });
+
+                    recipeHBox.getChildren().addAll(name, removeRecipeButton);
+                    displayRecipeVBox.getChildren().addAll(recipeImage, recipeHBox);
+                    mealPlanGrid.add(displayRecipeVBox, J, 1);
+                    recipeImage.setPreserveRatio(true);
+                    recipeImage.fitWidthProperty().bind(mealPlanGrid.widthProperty().divide(7));
+                    recipeImage.fitHeightProperty().bind(mealPlanGrid.heightProperty().subtract(60));
+                } catch (MissingContentException e) {
+                    //Display error message to the user, remove missing recipe from meal plan and re-render
+                    log.error(e.getMessage());
+                    Alert alert = new Alert(Alert.AlertType.ERROR);
+                    alert.setHeaderText("Missing recipe");
+                    alert.setContentText("A recipe with this code wasn't found. It will be removed from the meal plan");
+                    alert.show();
+                    mealPlan.remove(e.getCode());
                     render();
-                });
-
-                recipeHBox.getChildren().addAll(name, removeRecipeButton);
-                displayRecipeVBox.getChildren().addAll(recipeImage, recipeHBox);
-                mealPlanGrid.add(displayRecipeVBox, J, 1);
-                recipeImage.setPreserveRatio(true);
-                recipeImage.fitWidthProperty().bind(mealPlanGrid.widthProperty().divide(7));
-                recipeImage.fitHeightProperty().bind(mealPlanGrid.heightProperty().subtract(60));
+                }
             }, () -> {
+                //if this day has no code, display "plus" button
                 Button addRecipeButton = new Button();
                 addRecipeButton.setStyle("-fx-background-color: #dedede;" +
                         "-fx-background-radius: 10;");
@@ -128,11 +142,10 @@ public class MealPlanController extends BaseController {
         }
     }
 
-
     public void searchRecipes(LocalDate date) {
-            searchVBox = new VBox();
-            searchVBox.setMaxSize(800, 800);
-            searchVBox.setAlignment(Pos.CENTER);
+        searchVBox = new VBox();
+        searchVBox.setMaxSize(800, 800);
+        searchVBox.setAlignment(Pos.CENTER);
         TextField searchTextField = new TextField();
         searchTextField.setPromptText("Search for recipe");
         searchTextField.textProperty().addListener(e -> {
@@ -149,24 +162,24 @@ public class MealPlanController extends BaseController {
         stackPane.getChildren().add(searchVBox);
     }
 
-        private void drawRecipeSearchResults(LocalDate date) {
-            log.debug("Drawing search results");
-            VBox resultContainer = new VBox();
-            searchResults
-                    .forEach(
-                            result -> {
-                                IngredientSearchResultLabel resultLabel = new IngredientSearchResultLabel(result);
-                                resultLabel.setOnMouseClicked(e -> {
-                                    log.debug("User added recipe '{}' to mealplan for day {}.", result.getName(), date);
-                                    mealPlan.addRecipeToMealPlan(result, date);
-
-                                    stackPane.getChildren().remove(searchVBox);
-                                    render();
-                                });
-                                resultContainer.getChildren().add(resultLabel);
-                            }
-                    );
-            searchScrollPane.setContent(resultContainer);
+    private void drawRecipeSearchResults(LocalDate date) {
+        log.debug("Drawing search results");
+        VBox resultContainer = new VBox();
+        searchResults
+                .forEach(
+                        result -> {
+                            IngredientSearchResultLabel resultLabel = new IngredientSearchResultLabel(result);
+                            resultLabel.setOnMouseClicked(e -> {
+                                log.debug("User added recipe '{}' to mealplan for day {}.", result.getName(), date);
+                                mealPlan.addRecipeToMealPlan(result, date);
+
+                                stackPane.getChildren().remove(searchVBox);
+                                render();
+                            });
+                            resultContainer.getChildren().add(resultLabel);
+                        }
+                );
+        searchScrollPane.setContent(resultContainer);
     }
 
     @FXML
diff --git a/src/main/java/mi/hdm/controllers/RecipeEditorController.java b/src/main/java/mi/hdm/controllers/RecipeEditorController.java
index 4b624e0cca37983ff3a741d0cccc7622da2946cf..468c662c5d21a790d037a5b07353fc33ca35067c 100644
--- a/src/main/java/mi/hdm/controllers/RecipeEditorController.java
+++ b/src/main/java/mi/hdm/controllers/RecipeEditorController.java
@@ -11,6 +11,7 @@ import mi.hdm.components.IngredientSearchResultLabel;
 import mi.hdm.components.SelectedIngredientLabel;
 import mi.hdm.exceptions.InvalidIngredientException;
 import mi.hdm.exceptions.InvalidRecipeException;
+import mi.hdm.exceptions.MissingContentException;
 import mi.hdm.recipes.*;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
@@ -32,7 +33,7 @@ import static mi.hdm.helpers.Validation.isInteger;
 public class RecipeEditorController extends BaseController {
     private static final int ELEMENTS_PER_SEARCH_PAGE = 100;
 
-    private Recipe recipe;
+    private final Recipe recipe;
     private final RecipeManager recipeManager;
     private final CategoryManager categoryManager;
     private final IngredientManager ingredientManager;
@@ -41,7 +42,7 @@ public class RecipeEditorController extends BaseController {
     private List<RecipeComponent> searchResults;
     private final List<Category> selectedCategories;
     private final List<RecipeComponent> selectedIngredients;
-    private List<SelectedIngredientLabel> selectedIngredientLabels;
+    private final List<SelectedIngredientLabel> selectedIngredientLabels;
     private int currentPage = 0;
     private int maxPages = 0;
 
@@ -82,8 +83,13 @@ public class RecipeEditorController extends BaseController {
 
         searchResults = new ArrayList<>();
         selectedIngredients = new ArrayList<>();
-        recipe.getIngredients().forEach((code, amount) ->
-                selectedIngredients.add(componentFromCode(code))
+        recipe.getIngredients().forEach((code, amount) -> {
+                    try {
+                        selectedIngredients.add(componentFromCode(code));
+                    } catch (MissingContentException e) {
+                        throw new RuntimeException(e);
+                    }
+                }
         );
         recipeSearch = new RecipeSearch(recipeManager, ingredientManager);
         selectedIngredientsVbox = new VBox();
@@ -101,24 +107,45 @@ public class RecipeEditorController extends BaseController {
     private void displayRecipe() {
         nameTextField.setText(recipe.getName());
         descriptionTextArea.setText(recipe.getDescription());
-        //TODO: this is duplicate code (see around line 190) -> refactor into new method
+        final List<MissingContentException> missing = new ArrayList<>();
         recipe.getIngredients().forEach((code, amount) -> {
-            HBox ingredientHBox = new HBox();
-            Button deleteIngredientButton = new Button("X");
-            SelectedIngredientLabel label = new SelectedIngredientLabel(ingredientManager.getIngredient(code).get(), amount);
-            selectedIngredientLabels.add(label);
-            deleteIngredientButton.setStyle("-fx-text-fill: #d91c1c;" +
-                    "-fx-font-size: 12;" +
-                    "-fx-background-size: small;");
-            deleteIngredientButton.setOnAction(h -> {
+            //TODO: fetching ingredients needs to happen in constructor, add all to selected ingredients immediately, then
+            //TODO just stream over the list right here
+            try {
                 RecipeComponent c = componentFromCode(code);
-                log.debug("User deleted ingredient '{}' from recipe.", c.getName());
-                selectedIngredientLabels.remove(label);
-                selectedIngredientsVbox.getChildren().remove(ingredientHBox);
-            });
-            ingredientHBox.getChildren().addAll(label, deleteIngredientButton);
-            selectedIngredientsVbox.getChildren().add(ingredientHBox);
+                HBox ingredientHBox = new HBox();
+                Button deleteIngredientButton = new Button("X");
+                SelectedIngredientLabel label = new SelectedIngredientLabel(c, amount);
+                selectedIngredientLabels.add(label);
+                deleteIngredientButton.setStyle("-fx-text-fill: #d91c1c;" +
+                        "-fx-font-size: 12;");
+                deleteIngredientButton.setOnAction(h -> {
+                    selectedIngredients.remove(c);
+                    log.debug("User deleted ingredient '{}' from recipe.", c.getName());
+                    selectedIngredientLabels.remove(label);
+                    selectedIngredientsVbox.getChildren().remove(ingredientHBox);
+                });
+                ingredientHBox.getChildren().addAll(label, deleteIngredientButton);
+                selectedIngredientsVbox.getChildren().add(ingredientHBox);
+            } catch (MissingContentException e) {
+                missing.add(e);
+                log.warn("Missing ingredient in recipe: '{}'", e.getCode());
+            }
         });
+        if (missing.size() > 0) {
+            Alert alert = new Alert(Alert.AlertType.WARNING);
+            alert.setHeaderText("Missing ingredients");
+            alert.setContentText(missing.size() + " ingredients in this recipe do not exist anymore. They will be removed from the recipe.");
+            alert.show();
+            final Map<String, Integer> newIngredients = new HashMap<>(recipe.getIngredients());
+            for (MissingContentException e : missing) {
+                String code = e.getCode();
+                newIngredients.remove(code);
+                log.debug("Removed component with code '{}' from recipe", code);
+            }
+            recipe.setIngredientFromKeys(newIngredients);
+            log.info("Updated ingredients for recipe '{}', removed {} ingredients", recipe.getName(), missing.size());
+        }
         preparationTextArea.setText(String.join("\n", recipe.getPreparation()));
         prepTimeTextField.setText(String.valueOf(recipe.getPreparationTimeMins()));
         imagePathTextField.setText(recipe.getImageURL().toString());
@@ -270,16 +297,14 @@ public class RecipeEditorController extends BaseController {
         changeScene(View.RECIPE_VIEW, recipe);
     }
 
-    private RecipeComponent componentFromCode(String code) {
+    private RecipeComponent componentFromCode(String code) throws MissingContentException {
         RecipeComponent c;
         switch (code.charAt(0)) {
             case 'i' -> {
-                c = ingredientManager.getIngredient(code).get();
-                selectedIngredients.remove(c);
+                c = ingredientManager.getIngredient(code).orElseThrow(() -> new MissingContentException(code, Ingredient.class));
             }
             case 'r' -> {
-                c = recipeManager.getRecipe(code).get();
-                selectedIngredients.remove(c);
+                c = recipeManager.getRecipe(code).orElseThrow(() -> new MissingContentException(code, Recipe.class));
             }
             default -> throw new InvalidIngredientException("Recipe contained an invalid ingredient code: " + code);
         }
diff --git a/src/main/java/mi/hdm/exceptions/MissingContentException.java b/src/main/java/mi/hdm/exceptions/MissingContentException.java
new file mode 100644
index 0000000000000000000000000000000000000000..522161a6530edfd679fc6b2d410ebca310436eb3
--- /dev/null
+++ b/src/main/java/mi/hdm/exceptions/MissingContentException.java
@@ -0,0 +1,25 @@
+package mi.hdm.exceptions;
+
+import java.lang.reflect.Type;
+
+/**
+ * This exception is thrown when no object is found for a code.
+ */
+public class MissingContentException extends Exception {
+    private final Type type;
+    private final String code;
+
+    public MissingContentException(String code, Type type) {
+        super("Missing content exception: no instance of " + type + " was found with code '" + code + "'");
+        this.type = type;
+        this.code = code;
+    }
+
+    public Type getType() {
+        return type;
+    }
+
+    public String getCode() {
+        return code;
+    }
+}
diff --git a/src/main/java/mi/hdm/mealPlan/MealPlan.java b/src/main/java/mi/hdm/mealPlan/MealPlan.java
index 7f8cc38a30f80180b0d0bf7895f25f581b05952a..0a5cb667d8cfe272e20a27f44e9a95422924b955 100644
--- a/src/main/java/mi/hdm/mealPlan/MealPlan.java
+++ b/src/main/java/mi/hdm/mealPlan/MealPlan.java
@@ -123,6 +123,13 @@ public class MealPlan {
         return !(date.isBefore(LocalDate.now()) || invalid.isBefore(date));
     }
 
+    /**
+     * Removes the recipe with the specified code from the meal plan, if it exists
+     */
+    public void remove(String code) {
+        plan.values().remove(code);
+    }
+
     @Override
     public boolean equals(Object o) {
         if (o == this) return true;