about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2015-10-01 13:13:10 -0700
committerKartik K. Agaram <vc@akkartik.com>2015-10-01 13:13:10 -0700
commit4814bf94e75ffdcbd2a4093eb1ab67851980a37a (patch)
tree9fde405360c5499fa2ad4b25ca009ed3bcc1f57b
parent5fdd8e96adcf6f572888078caee62adbee1906a4 (diff)
downloadmu-4814bf94e75ffdcbd2a4093eb1ab67851980a37a.tar.gz
2226 - standardize warning format
Always show recipe name where error occurred. But don't show internal
'interactive' name for sandboxes, that's just confusing.

What started out as warnings are now ossifying into errors that halt all
execution. Is this how things went with C and Unix as well?
-rw-r--r--020run.cc7
-rw-r--r--021check_instruction.cc2
-rw-r--r--022arithmetic.cc38
-rw-r--r--023boolean.cc8
-rw-r--r--024jump.cc16
-rw-r--r--025compare.cc18
-rw-r--r--029tools.cc14
-rw-r--r--030container.cc12
-rw-r--r--031address.cc6
-rw-r--r--032array.cc18
-rw-r--r--033exclusive_container.cc6
-rw-r--r--034call.cc2
-rw-r--r--035call_ingredient.cc8
-rw-r--r--036call_reply.cc6
-rw-r--r--037recipe.cc4
-rw-r--r--038scheduler.cc18
-rw-r--r--039wait.cc6
-rw-r--r--040brace.cc4
-rw-r--r--041jump_target.cc8
-rw-r--r--042name.cc44
-rw-r--r--043new.cc18
-rw-r--r--044space.cc4
-rw-r--r--045space_surround.cc2
-rw-r--r--047global.cc2
-rw-r--r--048check_type_by_name.cc6
-rw-r--r--050scenario.cc10
-rw-r--r--053continuation.cc6
-rw-r--r--064random.cc4
-rw-r--r--070display.cc14
-rw-r--r--072scenario_screen.cc18
-rw-r--r--081run_interactive.cc12
-rw-r--r--082persist.cc10
-rw-r--r--edit/010-warnings.mu10
33 files changed, 186 insertions, 175 deletions
diff --git a/020run.cc b/020run.cc
index d1e405a7..69829a00 100644
--- a/020run.cc
+++ b/020run.cc
@@ -266,7 +266,7 @@ void write_memory(reagent x, vector<double> data) {
   if (is_literal(x)) return;
   long long int base = x.value;
   if (size_mismatch(x, data)) {
-    raise << current_recipe_name() << ": size mismatch in storing to " << x.original_string << " (" << size_of(x.types) << " vs " << SIZE(data) << ") at '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "size mismatch in storing to " << x.original_string << " (" << size_of(x.types) << " vs " << SIZE(data) << ") at '" << current_instruction().to_string() << "'\n" << end();
     return;
   }
   for (long long int offset = 0; offset < SIZE(data); ++offset) {
@@ -303,6 +303,11 @@ bool is_literal(const reagent& r) {
   return SIZE(r.types) == 1 && r.types.at(0) == 0;
 }
 
+// hook to suppress inserting recipe name into warnings
+string maybe(string s) {
+  return s + ": ";
+}
+
 // helper for tests
 void run(string form) {
   vector<recipe_ordinal> tmp = load(form);
diff --git a/021check_instruction.cc b/021check_instruction.cc
index 5b12af7c..cb332e7d 100644
--- a/021check_instruction.cc
+++ b/021check_instruction.cc
@@ -20,7 +20,7 @@ void check_instruction(const recipe_ordinal r) {
         }
         for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
           if (!types_match(inst.products.at(i), inst.ingredients.at(i))) {
-            raise << Recipe[r].name << ": can't copy " << inst.ingredients.at(i).original_string << " to " << inst.products.at(i).original_string << "; types don't match\n" << end();
+            raise << maybe(Recipe[r].name) << "can't copy " << inst.ingredients.at(i).original_string << " to " << inst.products.at(i).original_string << "; types don't match\n" << end();
             goto finish_checking_instruction;
           }
         }
diff --git a/022arithmetic.cc b/022arithmetic.cc
index 5dc8bcee..fbf3029a 100644
--- a/022arithmetic.cc
+++ b/022arithmetic.cc
@@ -9,16 +9,16 @@ case ADD: {
   // primary goal of these checks is to forbid address arithmetic
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_number(inst.ingredients.at(i))) {
-      raise << Recipe[r].name << ": 'add' requires number ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise << maybe(Recipe[r].name) << "'add' requires number ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
   if (SIZE(inst.products) > 1) {
-    raise << Recipe[r].name << ": 'add' yields exactly one product in '" << inst.to_string() << "'\n" << end();
+    raise << maybe(Recipe[r].name) << "'add' yields exactly one product in '" << inst.to_string() << "'\n" << end();
     break;
   }
   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
-    raise << Recipe[r].name << ": 'add' should yield a number, but got " << inst.products.at(0).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "'add' should yield a number, but got " << inst.products.at(0).original_string << '\n' << end();
     break;
   }
   break;
@@ -75,22 +75,22 @@ Recipe_ordinal["subtract"] = SUBTRACT;
 :(before "End Primitive Recipe Checks")
 case SUBTRACT: {
   if (inst.ingredients.empty()) {
-    raise << Recipe[r].name << ": 'subtract' has no ingredients\n" << end();
+    raise << maybe(Recipe[r].name) << "'subtract' has no ingredients\n" << end();
     break;
   }
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (is_raw(inst.ingredients.at(i))) continue;  // permit address offset computations in tests
     if (!is_mu_number(inst.ingredients.at(i))) {
-      raise << Recipe[r].name << ": 'subtract' requires number ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise << maybe(Recipe[r].name) << "'subtract' requires number ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
   if (SIZE(inst.products) > 1) {
-    raise << Recipe[r].name << ": 'subtract' yields exactly one product in '" << inst.to_string() << "'\n" << end();
+    raise << maybe(Recipe[r].name) << "'subtract' yields exactly one product in '" << inst.to_string() << "'\n" << end();
     break;
   }
   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
-    raise << Recipe[r].name << ": 'subtract' should yield a number, but got " << inst.products.at(0).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "'subtract' should yield a number, but got " << inst.products.at(0).original_string << '\n' << end();
     break;
   }
   break;
@@ -133,16 +133,16 @@ Recipe_ordinal["multiply"] = MULTIPLY;
 case MULTIPLY: {
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_number(inst.ingredients.at(i))) {
-      raise << Recipe[r].name << ": 'add' requires number ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise << maybe(Recipe[r].name) << "'add' requires number ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
   if (SIZE(inst.products) > 1) {
-    raise << Recipe[r].name << ": 'multiply' yields exactly one product in '" << inst.to_string() << "'\n" << end();
+    raise << maybe(Recipe[r].name) << "'multiply' yields exactly one product in '" << inst.to_string() << "'\n" << end();
     break;
   }
   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
-    raise << Recipe[r].name << ": 'multiply' should yield a number, but got " << inst.products.at(0).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "'multiply' should yield a number, but got " << inst.products.at(0).original_string << '\n' << end();
     break;
   }
   break;
@@ -185,21 +185,21 @@ Recipe_ordinal["divide"] = DIVIDE;
 :(before "End Primitive Recipe Checks")
 case DIVIDE: {
   if (inst.ingredients.empty()) {
-    raise << Recipe[r].name << ": 'divide' has no ingredients\n" << end();
+    raise << maybe(Recipe[r].name) << "'divide' has no ingredients\n" << end();
     break;
   }
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_number(inst.ingredients.at(i))) {
-      raise << Recipe[r].name << ": 'divide' requires number ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise << maybe(Recipe[r].name) << "'divide' requires number ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
   if (SIZE(inst.products) > 1) {
-    raise << Recipe[r].name << ": 'divide' yields exactly one product in '" << inst.to_string() << "'\n" << end();
+    raise << maybe(Recipe[r].name) << "'divide' yields exactly one product in '" << inst.to_string() << "'\n" << end();
     break;
   }
   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
-    raise << Recipe[r].name << ": 'divide' should yield a number, but got " << inst.products.at(0).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "'divide' should yield a number, but got " << inst.products.at(0).original_string << '\n' << end();
     break;
   }
   break;
@@ -243,20 +243,20 @@ Recipe_ordinal["divide-with-remainder"] = DIVIDE_WITH_REMAINDER;
 :(before "End Primitive Recipe Checks")
 case DIVIDE_WITH_REMAINDER: {
   if (SIZE(inst.ingredients) != 2) {
-    raise << current_recipe_name() << ": 'divide-with-remainder' requires exactly two ingredients, but got '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "'divide-with-remainder' requires exactly two ingredients, but got '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0)) || !is_mu_number(inst.ingredients.at(1))) {
-    raise << current_recipe_name() << ": 'divide-with-remainder' requires number ingredients, but got '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "'divide-with-remainder' requires number ingredients, but got '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   if (SIZE(inst.products) > 2) {
-    raise << Recipe[r].name << ": 'divide-with-remainder' yields two products in '" << inst.to_string() << "'\n" << end();
+    raise << maybe(Recipe[r].name) << "'divide-with-remainder' yields two products in '" << inst.to_string() << "'\n" << end();
     break;
   }
   for (long long int i = 0; i < SIZE(inst.products); ++i) {
     if (!is_dummy(inst.products.at(i)) && !is_mu_number(inst.products.at(i))) {
-      raise << Recipe[r].name << ": 'divide-with-remainder' should yield a number, but got " << inst.products.at(i).original_string << '\n' << end();
+      raise << maybe(Recipe[r].name) << "'divide-with-remainder' should yield a number, but got " << inst.products.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
@@ -268,7 +268,7 @@ case DIVIDE_WITH_REMAINDER: {
   long long int a = static_cast<long long int>(ingredients.at(0).at(0));
   long long int b = static_cast<long long int>(ingredients.at(1).at(0));
   if (b == 0) {
-    raise << current_recipe_name() << ": divide by zero in '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "divide by zero in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   long long int quotient = a / b;
diff --git a/023boolean.cc b/023boolean.cc
index e556f47c..24752e72 100644
--- a/023boolean.cc
+++ b/023boolean.cc
@@ -8,7 +8,7 @@ Recipe_ordinal["and"] = AND;
 case AND: {
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_scalar(inst.ingredients.at(i))) {
-      raise << Recipe[r].name << ": 'and' requires boolean ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise << maybe(Recipe[r].name) << "'and' requires boolean ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
@@ -58,7 +58,7 @@ Recipe_ordinal["or"] = OR;
 case OR: {
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_scalar(inst.ingredients.at(i))) {
-      raise << Recipe[r].name << ": 'and' requires boolean ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise << maybe(Recipe[r].name) << "'and' requires boolean ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
@@ -107,12 +107,12 @@ Recipe_ordinal["not"] = NOT;
 :(before "End Primitive Recipe Checks")
 case NOT: {
   if (SIZE(inst.products) > SIZE(inst.ingredients)) {
-    raise << Recipe[r].name << ": 'not' cannot have fewer ingredients than products in '" << inst.to_string() << "'\n" << end();
+    raise << maybe(Recipe[r].name) << "'not' cannot have fewer ingredients than products in '" << inst.to_string() << "'\n" << end();
     break;
   }
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_scalar(inst.ingredients.at(i))) {
-      raise << Recipe[r].name << ": 'not' requires boolean ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise << maybe(Recipe[r].name) << "'not' requires boolean ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
diff --git a/024jump.cc b/024jump.cc
index dabe33bb..b249535e 100644
--- a/024jump.cc
+++ b/024jump.cc
@@ -16,11 +16,11 @@ Recipe_ordinal["jump"] = JUMP;
 :(before "End Primitive Recipe Checks")
 case JUMP: {
   if (SIZE(inst.ingredients) != 1) {
-    raise << Recipe[r].name << ": 'jump' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
+    raise << maybe(Recipe[r].name) << "'jump' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
     break;
   }
   if (!is_mu_scalar(inst.ingredients.at(0))) {
-    raise << Recipe[r].name << ": first ingredient of 'jump' should be a label or offset, but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "first ingredient of 'jump' should be a label or offset, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   break;
@@ -55,15 +55,15 @@ Recipe_ordinal["jump-if"] = JUMP_IF;
 :(before "End Primitive Recipe Checks")
 case JUMP_IF: {
   if (SIZE(inst.ingredients) != 2) {
-    raise << Recipe[r].name << ": 'jump-if' requires exactly two ingredients, but got " << inst.to_string() << '\n' << end();
+    raise << maybe(Recipe[r].name) << "'jump-if' requires exactly two ingredients, but got " << inst.to_string() << '\n' << end();
     break;
   }
   if (!is_mu_scalar(inst.ingredients.at(0))) {
-    raise << Recipe[r].name << ": 'jump-if' requires a boolean for its first ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "'jump-if' requires a boolean for its first ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   if (!is_mu_scalar(inst.ingredients.at(1))) {
-    raise << Recipe[r].name << ": 'jump-if' requires a label or offset for its second ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "'jump-if' requires a label or offset for its second ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   break;
@@ -107,15 +107,15 @@ Recipe_ordinal["jump-unless"] = JUMP_UNLESS;
 :(before "End Primitive Recipe Checks")
 case JUMP_UNLESS: {
   if (SIZE(inst.ingredients) != 2) {
-    raise << Recipe[r].name << ": 'jump-unless' requires exactly two ingredients, but got " << inst.to_string() << '\n' << end();
+    raise << maybe(Recipe[r].name) << "'jump-unless' requires exactly two ingredients, but got " << inst.to_string() << '\n' << end();
     break;
   }
   if (!is_mu_scalar(inst.ingredients.at(0))) {
-    raise << Recipe[r].name << ": 'jump-unless' requires a boolean for its first ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "'jump-unless' requires a boolean for its first ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   if (!is_mu_scalar(inst.ingredients.at(1))) {
-    raise << Recipe[r].name << ": 'jump-unless' requires a label or offset for its second ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "'jump-unless' requires a label or offset for its second ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   break;
diff --git a/025compare.cc b/025compare.cc
index 745111d8..74f1e4f1 100644
--- a/025compare.cc
+++ b/025compare.cc
@@ -7,7 +7,7 @@ Recipe_ordinal["equal"] = EQUAL;
 :(before "End Primitive Recipe Checks")
 case EQUAL: {
   if (SIZE(inst.ingredients) <= 1) {
-    raise << Recipe[r].name << ": 'equal' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
+    raise << maybe(Recipe[r].name) << "'equal' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
     break;
   }
   break;
@@ -66,12 +66,12 @@ Recipe_ordinal["greater-than"] = GREATER_THAN;
 :(before "End Primitive Recipe Checks")
 case GREATER_THAN: {
   if (SIZE(inst.ingredients) <= 1) {
-    raise << Recipe[r].name << ": 'greater-than' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
+    raise << maybe(Recipe[r].name) << "'greater-than' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
     break;
   }
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_number(inst.ingredients.at(i))) {
-      raise << Recipe[r].name << ": 'greater-than' can only compare numbers; got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise << maybe(Recipe[r].name) << "'greater-than' can only compare numbers; got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
@@ -125,12 +125,12 @@ Recipe_ordinal["lesser-than"] = LESSER_THAN;
 :(before "End Primitive Recipe Checks")
 case LESSER_THAN: {
   if (SIZE(inst.ingredients) <= 1) {
-    raise << Recipe[r].name << ": 'lesser-than' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
+    raise << maybe(Recipe[r].name) << "'lesser-than' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
     break;
   }
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_number(inst.ingredients.at(i))) {
-      raise << Recipe[r].name << ": 'lesser-than' can only compare numbers; got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise << maybe(Recipe[r].name) << "'lesser-than' can only compare numbers; got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
@@ -184,12 +184,12 @@ Recipe_ordinal["greater-or-equal"] = GREATER_OR_EQUAL;
 :(before "End Primitive Recipe Checks")
 case GREATER_OR_EQUAL: {
   if (SIZE(inst.ingredients) <= 1) {
-    raise << Recipe[r].name << ": 'greater-or-equal' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
+    raise << maybe(Recipe[r].name) << "'greater-or-equal' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
     break;
   }
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_number(inst.ingredients.at(i))) {
-      raise << Recipe[r].name << ": 'greater-or-equal' can only compare numbers; got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise << maybe(Recipe[r].name) << "'greater-or-equal' can only compare numbers; got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
@@ -251,12 +251,12 @@ Recipe_ordinal["lesser-or-equal"] = LESSER_OR_EQUAL;
 :(before "End Primitive Recipe Checks")
 case LESSER_OR_EQUAL: {
   if (SIZE(inst.ingredients) <= 1) {
-    raise << Recipe[r].name << ": 'lesser-or-equal' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
+    raise << maybe(Recipe[r].name) << "'lesser-or-equal' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
     break;
   }
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_number(inst.ingredients.at(i))) {
-      raise << Recipe[r].name << ": 'lesser-or-equal' can only compare numbers; got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise << maybe(Recipe[r].name) << "'lesser-or-equal' can only compare numbers; got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
diff --git a/029tools.cc b/029tools.cc
index e09b9d7a..1cf10474 100644
--- a/029tools.cc
+++ b/029tools.cc
@@ -13,15 +13,15 @@ Recipe_ordinal["trace"] = TRACE;
 :(before "End Primitive Recipe Checks")
 case TRACE: {
   if (SIZE(inst.ingredients) < 3) {
-    raise << Recipe[r].name << ": 'trace' takes three or more ingredients rather than '" << inst.to_string() << "'\n" << end();
+    raise << maybe(Recipe[r].name) << "'trace' takes three or more ingredients rather than '" << inst.to_string() << "'\n" << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0))) {
-    raise << Recipe[r].name << ": first ingredient of 'trace' should be a number (depth), but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "first ingredient of 'trace' should be a number (depth), but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   if (!is_literal_string(inst.ingredients.at(1))) {
-    raise << Recipe[r].name << ": second ingredient of 'trace' should be a literal string (label), but got " << inst.ingredients.at(1).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "second ingredient of 'trace' should be a literal string (label), but got " << inst.ingredients.at(1).original_string << '\n' << end();
     break;
   }
   break;
@@ -182,15 +182,15 @@ Recipe_ordinal["assert"] = ASSERT;
 :(before "End Primitive Recipe Checks")
 case ASSERT: {
   if (SIZE(inst.ingredients) != 2) {
-    raise << Recipe[r].name << ": 'assert' takes exactly two ingredients rather than '" << inst.to_string() << "'\n" << end();
+    raise << maybe(Recipe[r].name) << "'assert' takes exactly two ingredients rather than '" << inst.to_string() << "'\n" << end();
     break;
   }
   if (!is_mu_scalar(inst.ingredients.at(0))) {
-    raise << Recipe[r].name << ": 'assert' requires a boolean for its first ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "'assert' requires a boolean for its first ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   if (!is_literal_string(inst.ingredients.at(1))) {
-    raise << Recipe[r].name << ": 'assert' requires a literal string for its second ingredient, but got " << inst.ingredients.at(1).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "'assert' requires a literal string for its second ingredient, but got " << inst.ingredients.at(1).original_string << '\n' << end();
     break;
   }
   break;
@@ -247,7 +247,7 @@ Recipe_ordinal["$system"] = _SYSTEM;
 :(before "End Primitive Recipe Checks")
 case _SYSTEM: {
   if (inst.ingredients.empty()) {
-    raise << Recipe[r].name << ": '$system' requires exactly one ingredient, but got none\n" << end();
+    raise << maybe(Recipe[r].name) << "'$system' requires exactly one ingredient, but got none\n" << end();
     break;
   }
   break;
diff --git a/030container.cc b/030container.cc
index 19d3a5af..142688eb 100644
--- a/030container.cc
+++ b/030container.cc
@@ -125,13 +125,13 @@ Recipe_ordinal["get"] = GET;
 :(before "End Primitive Recipe Implementations")
 case GET: {
   if (SIZE(ingredients) != 2) {
-    raise << current_recipe_name() << ": 'get' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "'get' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   reagent base = current_instruction().ingredients.at(0);
   long long int base_address = base.value;
   if (base_address == 0) {
-    raise << current_recipe_name() << ": tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   if (base.types.empty() || Type[base.types.at(0)].kind != container) {
@@ -140,7 +140,7 @@ case GET: {
   }
   type_ordinal base_type = base.types.at(0);
   if (!is_literal(current_instruction().ingredients.at(1))) {
-    raise << current_recipe_name() << ": second ingredient of 'get' should have type 'offset', but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "second ingredient of 'get' should have type 'offset', but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
     break;
   }
   assert(scalar(ingredients.at(1)));
@@ -151,7 +151,7 @@ case GET: {
   }
   trace(Primitive_recipe_depth, "run") << "address to copy is " << src << end();
   if (offset < 0 || offset >= SIZE(Type[base_type].elements)) {
-    raise << current_recipe_name() << ": invalid offset " << offset << " for " << Type[base_type].name << '\n' << end();
+    raise << maybe(current_recipe_name()) << "invalid offset " << offset << " for " << Type[base_type].name << '\n' << end();
     break;
   }
   type_ordinal src_type = Type[base_type].elements.at(offset).at(0);
@@ -211,7 +211,7 @@ case GET_ADDRESS: {
   reagent base = current_instruction().ingredients.at(0);
   long long int base_address = base.value;
   if (base_address == 0) {
-    raise << current_recipe_name() << ": tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   if (base.types.empty() || Type[base.types.at(0)].kind != container) {
@@ -220,7 +220,7 @@ case GET_ADDRESS: {
   }
   type_ordinal base_type = base.types.at(0);
   if (!is_literal(current_instruction().ingredients.at(1))) {
-    raise << current_recipe_name() << ": second ingredient of 'get-address' should have type 'offset', but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "second ingredient of 'get-address' should have type 'offset', but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
     break;
   }
   assert(scalar(ingredients.at(1)));
diff --git a/031address.cc b/031address.cc
index 5514b8c2..c074fe76 100644
--- a/031address.cc
+++ b/031address.cc
@@ -52,12 +52,12 @@ reagent lookup_memory(reagent x) {
   static const type_ordinal ADDRESS = Type_ordinal["address"];
   reagent result;
   if (x.types.empty() || x.types.at(0) != ADDRESS) {
-    raise << current_recipe_name() << ": tried to /lookup " << x.original_string << " but it isn't an address\n" << end();
+    raise << maybe(current_recipe_name()) << "tried to /lookup " << x.original_string << " but it isn't an address\n" << end();
     return result;
   }
   // compute value
   if (x.value == 0) {
-    raise << current_recipe_name() << ": tried to /lookup 0\n" << end();
+    raise << maybe(current_recipe_name()) << "tried to /lookup 0\n" << end();
     return result;
   }
   result.set_value(Memory[x.value]);
@@ -184,7 +184,7 @@ Recipe_ordinal["$dump"] = _DUMP;
 :(before "End Primitive Recipe Implementations")
 case _DUMP: {
   reagent after_canonize = canonize(current_instruction().ingredients.at(0));
-  cerr << current_recipe_name() << ": " << current_instruction().ingredients.at(0).name << ' ' << no_scientific(current_instruction().ingredients.at(0).value) << " => " << no_scientific(after_canonize.value) << " => " << no_scientific(Memory[after_canonize.value]) << '\n';
+  cerr << maybe(current_recipe_name()) << "" << current_instruction().ingredients.at(0).name << ' ' << no_scientific(current_instruction().ingredients.at(0).value) << " => " << no_scientific(after_canonize.value) << " => " << no_scientific(Memory[after_canonize.value]) << '\n';
   break;
 }
 
diff --git a/032array.cc b/032array.cc
index 31f4832e..5ed97e7f 100644
--- a/032array.cc
+++ b/032array.cc
@@ -102,7 +102,7 @@ if (x.types.at(0) == Type_ordinal["array"]) return false;
 :(before "End size_of(reagent) Cases")
 if (r.types.at(0) == Type_ordinal["array"]) {
   if (SIZE(r.types) == 1) {
-    raise << current_recipe_name() << ": '" << r.original_string << "' is an array of what?\n" << end();
+    raise << maybe(current_recipe_name()) << "'" << r.original_string << "' is an array of what?\n" << end();
     return 1;
   }
   // skip the 'array' type to get at the element type
@@ -139,7 +139,7 @@ Recipe_ordinal["index"] = INDEX;
 :(before "End Primitive Recipe Implementations")
 case INDEX: {
   if (SIZE(current_instruction().ingredients) != 2) {
-    raise << current_recipe_name() << ": 'index' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "'index' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   reagent base = canonize(current_instruction().ingredients.at(0));
@@ -149,14 +149,14 @@ case INDEX: {
   }
   long long int base_address = base.value;
   if (base_address == 0) {
-    raise << current_recipe_name() << ": tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   reagent offset = canonize(current_instruction().ingredients.at(1));
   vector<double> offset_val(read_memory(offset));
   vector<type_ordinal> element_type = array_element(base.types);
   if (offset_val.at(0) < 0 || offset_val.at(0) >= Memory[base_address]) {
-    raise << current_recipe_name() << ": invalid index " << no_scientific(offset_val.at(0)) << '\n' << end();
+    raise << maybe(current_recipe_name()) << "invalid index " << no_scientific(offset_val.at(0)) << '\n' << end();
     break;
   }
   long long int src = base_address + 1 + offset_val.at(0)*size_of(element_type);
@@ -234,7 +234,7 @@ Recipe_ordinal["index-address"] = INDEX_ADDRESS;
 :(before "End Primitive Recipe Implementations")
 case INDEX_ADDRESS: {
   if (SIZE(current_instruction().ingredients) != 2) {
-    raise << current_recipe_name() << ": 'index-address' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "'index-address' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   reagent base = canonize(current_instruction().ingredients.at(0));
@@ -244,14 +244,14 @@ case INDEX_ADDRESS: {
   }
   long long int base_address = base.value;
   if (base_address == 0) {
-    raise << current_recipe_name() << ": tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   reagent offset = canonize(current_instruction().ingredients.at(1));
   vector<double> offset_val(read_memory(offset));
   vector<type_ordinal> element_type = array_element(base.types);
   if (offset_val.at(0) < 0 || offset_val.at(0) >= Memory[base_address]) {
-    raise << current_recipe_name() << ": invalid index " << no_scientific(offset_val.at(0)) << '\n' << end();
+    raise << maybe(current_recipe_name()) << "invalid index " << no_scientific(offset_val.at(0)) << '\n' << end();
     break;
   }
   long long int result = base_address + 1 + offset_val.at(0)*size_of(element_type);
@@ -309,7 +309,7 @@ Recipe_ordinal["length"] = LENGTH;
 :(before "End Primitive Recipe Implementations")
 case LENGTH: {
   if (SIZE(current_instruction().ingredients) != 1) {
-    raise << current_recipe_name() << ": 'length' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "'length' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   reagent x = canonize(current_instruction().ingredients.at(0));
@@ -318,7 +318,7 @@ case LENGTH: {
     break;
   }
   if (x.value == 0) {
-    raise << current_recipe_name() << ": tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   products.resize(1);
diff --git a/033exclusive_container.cc b/033exclusive_container.cc
index 58276b9a..ae4a7e4c 100644
--- a/033exclusive_container.cc
+++ b/033exclusive_container.cc
@@ -84,13 +84,13 @@ Recipe_ordinal["maybe-convert"] = MAYBE_CONVERT;
 :(before "End Primitive Recipe Implementations")
 case MAYBE_CONVERT: {
   if (SIZE(ingredients) != 2) {
-    raise << current_recipe_name() << ": 'maybe-convert' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "'maybe-convert' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   reagent base = canonize(current_instruction().ingredients.at(0));
   long long int base_address = base.value;
   if (base_address == 0) {
-    raise << current_recipe_name() << ": tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "tried to access location 0 in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   if (base.types.empty() || Type[base.types.at(0)].kind != exclusive_container) {
@@ -98,7 +98,7 @@ case MAYBE_CONVERT: {
     break;
   }
   if (!is_literal(current_instruction().ingredients.at(1))) {
-    raise << current_recipe_name() << ": second ingredient of 'maybe-convert' should have type 'variant', but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "second ingredient of 'maybe-convert' should have type 'variant', but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
     break;
   }
   long long int tag = current_instruction().ingredients.at(1).value;
diff --git a/034call.cc b/034call.cc
index 4bf7140a..f1c82f7f 100644
--- a/034call.cc
+++ b/034call.cc
@@ -81,7 +81,7 @@ inline const instruction& current_instruction() {
 default: {
   // not a primitive; try to look up the book of recipes
   if (Recipe.find(current_instruction().operation) == Recipe.end()) {
-    raise << current_recipe_name() << ": undefined operation in '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "undefined operation in '" << current_instruction().to_string() << "'\n" << end();
     // stop running this instruction immediately
     ++current_step_index();
     continue;
diff --git a/035call_ingredient.cc b/035call_ingredient.cc
index 8daca0cf..3cfc44ce 100644
--- a/035call_ingredient.cc
+++ b/035call_ingredient.cc
@@ -38,7 +38,7 @@ Recipe_ordinal["next-ingredient"] = NEXT_INGREDIENT;
 :(before "End Primitive Recipe Implementations")
 case NEXT_INGREDIENT: {
   if (!ingredients.empty()) {
-    raise << current_recipe_name() << ": 'next-ingredient' didn't expect any ingredients in '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "'next-ingredient' didn't expect any ingredients in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   assert(!Current_routine->calls.empty());
@@ -51,7 +51,7 @@ case NEXT_INGREDIENT: {
   }
   else {
     if (SIZE(current_instruction().products) < 2)
-      raise << current_recipe_name() << ": no ingredient to save in " << current_instruction().products.at(0).original_string << '\n' << end();
+      raise << maybe(current_recipe_name()) << "no ingredient to save in " << current_instruction().products.at(0).original_string << '\n' << end();
     products.resize(2);
     products.at(0).push_back(0);  // todo: will fail noisily if we try to read a compound value
     products.at(1).push_back(0);
@@ -112,11 +112,11 @@ Recipe_ordinal["ingredient"] = INGREDIENT;
 :(before "End Primitive Recipe Implementations")
 case INGREDIENT: {
   if (SIZE(ingredients) != 1) {
-    raise << current_recipe_name() << ": 'ingredient' expects exactly one ingredient, but got '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "'ingredient' expects exactly one ingredient, but got '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   if (!is_literal(current_instruction().ingredients.at(0))) {
-    raise << current_recipe_name() << ": 'ingredient' expects a literal ingredient, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "'ingredient' expects a literal ingredient, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   assert(scalar(ingredients.at(0)));
diff --git a/036call_reply.cc b/036call_reply.cc
index 2cb4922e..cc146835 100644
--- a/036call_reply.cc
+++ b/036call_reply.cc
@@ -37,14 +37,14 @@ case REPLY: {
     if (has_property(reply_inst.ingredients.at(i), "same-as-ingredient")) {
       vector<string> tmp = property(reply_inst.ingredients.at(i), "same-as-ingredient");
       if (SIZE(tmp) != 1) {
-        raise << current_recipe_name() << ": 'same-as-ingredient' metadata should take exactly one value in " << reply_inst.to_string() << '\n' << end();
+        raise << maybe(current_recipe_name()) << "'same-as-ingredient' metadata should take exactly one value in " << reply_inst.to_string() << '\n' << end();
         goto finish_reply;
       }
       long long int ingredient_index = to_integer(tmp.at(0));
       if (ingredient_index >= SIZE(caller_instruction.ingredients))
-        raise << current_recipe_name() << ": 'same-as-ingredient' metadata overflows ingredients in: " << caller_instruction.to_string() << '\n' << end();
+        raise << maybe(current_recipe_name()) << "'same-as-ingredient' metadata overflows ingredients in: " << caller_instruction.to_string() << '\n' << end();
       if (!is_dummy(caller_instruction.products.at(i)) && caller_instruction.products.at(i).value != caller_instruction.ingredients.at(ingredient_index).value)
-        raise << current_recipe_name() << ": 'same-as-ingredient' product from call to " << callee << " must be " << caller_instruction.ingredients.at(ingredient_index).original_string << " rather than " << caller_instruction.products.at(i).original_string << '\n' << end();
+        raise << maybe(current_recipe_name()) << "'same-as-ingredient' product from call to " << callee << " must be " << caller_instruction.ingredients.at(ingredient_index).original_string << " rather than " << caller_instruction.products.at(i).original_string << '\n' << end();
     }
   }
   // End Reply
diff --git a/037recipe.cc b/037recipe.cc
index 7ec0191b..bbc197c8 100644
--- a/037recipe.cc
+++ b/037recipe.cc
@@ -43,12 +43,12 @@ Recipe_ordinal["call"] = CALL;
 :(before "End Primitive Recipe Implementations")
 case CALL: {
   if (ingredients.empty()) {
-    raise << current_recipe_name() << ": 'call' requires at least one ingredient (the recipe to call)\n" << end();
+    raise << maybe(current_recipe_name()) << "'call' requires at least one ingredient (the recipe to call)\n" << end();
     break;
   }
   // Begin Call
   if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'call' should be a recipe, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'call' should be a recipe, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   // todo: when we start doing type checking this will be a prime point of
diff --git a/038scheduler.cc b/038scheduler.cc
index 2e0e0322..2ae1b3b3 100644
--- a/038scheduler.cc
+++ b/038scheduler.cc
@@ -333,11 +333,11 @@ Recipe_ordinal["routine-state"] = ROUTINE_STATE;
 :(before "End Primitive Recipe Implementations")
 case ROUTINE_STATE: {
   if (SIZE(ingredients) != 1) {
-    raise << current_recipe_name() << ": 'routine-state' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "'routine-state' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
     break;
   }
   if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'routine-state' should be a routine id generated by 'start-running', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'routine-state' should be a routine id generated by 'start-running', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   long long int id = ingredients.at(0).at(0);
@@ -362,11 +362,11 @@ Recipe_ordinal["restart"] = RESTART;
 :(before "End Primitive Recipe Implementations")
 case RESTART: {
   if (SIZE(ingredients) != 1) {
-    raise << current_recipe_name() << ": 'restart' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "'restart' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
     break;
   }
   if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'restart' should be a routine id generated by 'start-running', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'restart' should be a routine id generated by 'start-running', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   long long int id = ingredients.at(0).at(0);
@@ -386,11 +386,11 @@ Recipe_ordinal["stop"] = STOP;
 :(before "End Primitive Recipe Implementations")
 case STOP: {
   if (SIZE(ingredients) != 1) {
-    raise << current_recipe_name() << ": 'stop' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "'stop' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
     break;
   }
   if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'stop' should be a routine id generated by 'start-running', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'stop' should be a routine id generated by 'start-running', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   long long int id = ingredients.at(0).at(0);
@@ -460,15 +460,15 @@ Recipe_ordinal["limit-time"] = LIMIT_TIME;
 :(before "End Primitive Recipe Implementations")
 case LIMIT_TIME: {
   if (SIZE(ingredients) != 2) {
-    raise << current_recipe_name() << ": 'limit-time' requires exactly two ingredient, but got " << current_instruction().to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "'limit-time' requires exactly two ingredient, but got " << current_instruction().to_string() << '\n' << end();
     break;
   }
   if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'limit-time' should be a routine id generated by 'start-running', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'limit-time' should be a routine id generated by 'start-running', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   if (!scalar(ingredients.at(1))) {
-    raise << current_recipe_name() << ": second ingredient of 'limit-time' should be a number (of instructions to run for), but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "second ingredient of 'limit-time' should be a number (of instructions to run for), but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
     break;
   }
   long long int id = ingredients.at(0).at(0);
diff --git a/039wait.cc b/039wait.cc
index 9a76e309..955ab4a8 100644
--- a/039wait.cc
+++ b/039wait.cc
@@ -91,15 +91,15 @@ Recipe_ordinal["wait-for-routine"] = WAIT_FOR_ROUTINE;
 :(before "End Primitive Recipe Implementations")
 case WAIT_FOR_ROUTINE: {
   if (SIZE(ingredients) != 1) {
-    raise << current_recipe_name() << ": 'wait-for-routine' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "'wait-for-routine' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
     break;
   }
   if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'wait-for-routine' should be a routine id generated by 'start-running', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'wait-for-routine' should be a routine id generated by 'start-running', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   if (ingredients.at(0).at(0) == Current_routine->id) {
-    raise << current_recipe_name() << ": routine can't wait for itself! " << current_instruction().to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "routine can't wait for itself! " << current_instruction().to_string() << '\n' << end();
     break;
   }
   Current_routine->state = WAITING;
diff --git a/040brace.cc b/040brace.cc
index a26364e1..d5e89a6c 100644
--- a/040brace.cc
+++ b/040brace.cc
@@ -43,7 +43,7 @@ void transform_braces(const recipe_ordinal r) {
   for (long long int index = 0; index < SIZE(Recipe[r].steps); ++index) {
     const instruction& inst = Recipe[r].steps.at(index);
     if (inst.label == "{") {
-      trace("brace") << Recipe[r].name << ": push (open, " << index << ")" << end();
+      trace("brace") << maybe(Recipe[r].name) << "push (open, " << index << ")" << end();
       braces.push_back(pair<int,long long int>(OPEN, index));
     }
     if (inst.label == "}") {
@@ -132,7 +132,7 @@ long long int matching_brace(long long int index, const list<pair<int, long long
     stacksize += (p->first ? 1 : -1);
     if (stacksize == 0) return p->second;
   }
-  raise << Recipe[r].name << ": unbalanced '{'\n" << end();
+  raise << maybe(Recipe[r].name) << "unbalanced '{'\n" << end();
   return SIZE(Recipe[r].steps);  // exit current routine
 }
 
diff --git a/041jump_target.cc b/041jump_target.cc
index aaa01355..fad1e3c7 100644
--- a/041jump_target.cc
+++ b/041jump_target.cc
@@ -31,7 +31,7 @@ void transform_labels(const recipe_ordinal r) {
         offset[inst.label] = i;
       }
       else {
-        raise << Recipe[r].name << ": duplicate label '" << inst.label << "'" << end();
+        raise << maybe(Recipe[r].name) << "duplicate label '" << inst.label << "'" << end();
         // have all jumps skip some random but noticeable and deterministic amount of code
         offset[inst.label] = 9999;
       }
@@ -60,19 +60,19 @@ void transform_labels(const recipe_ordinal r) {
 :(code)
 void replace_offset(reagent& x, /*const*/ map<string, long long int>& offset, const long long int current_offset, const recipe_ordinal r) {
   if (!is_literal(x)) {
-    raise << Recipe[r].name << ": jump target must be offset or label but is " << x.original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "jump target must be offset or label but is " << x.original_string << '\n' << end();
     x.set_value(0);  // no jump by default
     return;
   }
   assert(!x.initialized);
   if (is_integer(x.name)) return;  // non-labels will be handled like other number operands
   if (!is_jump_target(x.name)) {
-    raise << Recipe[r].name << ": can't jump to label " << x.name << '\n' << end();
+    raise << maybe(Recipe[r].name) << "can't jump to label " << x.name << '\n' << end();
     x.set_value(0);  // no jump by default
     return;
   }
   if (offset.find(x.name) == offset.end()) {
-    raise << Recipe[r].name << ": can't find label " << x.name << '\n' << end();
+    raise << maybe(Recipe[r].name) << "can't find label " << x.name << '\n' << end();
     x.set_value(0);  // no jump by default
     return;
   }
diff --git a/042name.cc b/042name.cc
index 060f59e1..fbc83abd 100644
--- a/042name.cc
+++ b/042name.cc
@@ -15,7 +15,7 @@ recipe main [
 recipe main [
   x:number <- copy y:number
 ]
-+warn: use before set: y in main
++warn: main: use before set: y
 
 :(after "int main")
   Transform.push_back(transform_names);
@@ -42,16 +42,16 @@ void transform_names(const recipe_ordinal r) {
     for (long long int in = 0; in < SIZE(inst.ingredients); ++in) {
       if (is_numeric_location(inst.ingredients.at(in))) numeric_locations_used = true;
       if (is_named_location(inst.ingredients.at(in))) names_used = true;
-      if (disqualified(inst.ingredients.at(in), inst)) continue;
+      if (disqualified(inst.ingredients.at(in), inst, Recipe[r].name)) continue;
       if (!already_transformed(inst.ingredients.at(in), names)) {
-        raise << "use before set: " << inst.ingredients.at(in).name << " in " << Recipe[r].name << '\n' << end();
+        raise << maybe(Recipe[r].name) << "use before set: " << inst.ingredients.at(in).name << '\n' << end();
       }
       inst.ingredients.at(in).set_value(lookup_name(inst.ingredients.at(in), r));
     }
     for (long long int out = 0; out < SIZE(inst.products); ++out) {
       if (is_numeric_location(inst.products.at(out))) numeric_locations_used = true;
       if (is_named_location(inst.products.at(out))) names_used = true;
-      if (disqualified(inst.products.at(out), inst)) continue;
+      if (disqualified(inst.products.at(out), inst, Recipe[r].name)) continue;
       if (names.find(inst.products.at(out).name) == names.end()) {
         trace("name") << "assign " << inst.products.at(out).name << " " << curr_idx << end();
         names[inst.products.at(out).name] = curr_idx;
@@ -61,12 +61,12 @@ void transform_names(const recipe_ordinal r) {
     }
   }
   if (names_used && numeric_locations_used)
-    raise << "mixing variable names and numeric addresses in " << Recipe[r].name << '\n' << end();
+    raise << maybe(Recipe[r].name) << "mixing variable names and numeric addresses\n" << end();
 }
 
-bool disqualified(/*mutable*/ reagent& x, const instruction& inst) {
+bool disqualified(/*mutable*/ reagent& x, const instruction& inst, const string& recipe_name) {
   if (x.types.empty()) {
-    raise << "missing type for " << x.original_string << " in '" << inst.to_string() << "'\n" << end();
+    raise << maybe(recipe_name) << "missing type for " << x.original_string << " in '" << inst.to_string() << "'\n" << end();
     return true;
   }
   if (is_raw(x)) return true;
@@ -85,20 +85,20 @@ long long int lookup_name(const reagent& r, const recipe_ordinal default_recipe)
   return Name[default_recipe][r.name];
 }
 
-type_ordinal skip_addresses(const vector<type_ordinal>& types) {
+type_ordinal skip_addresses(const vector<type_ordinal>& types, const string& recipe_name) {
   for (long long int i = 0; i < SIZE(types); ++i) {
     if (types.at(i) != Type_ordinal["address"]) return types.at(i);
   }
-  raise << "expected a container" << '\n' << end();
+  raise << maybe(recipe_name) << "expected a container" << '\n' << end();
   return -1;
 }
 
-int find_element_name(const type_ordinal t, const string& name) {
+int find_element_name(const type_ordinal t, const string& name, const string& recipe_name) {
   const type_info& container = Type[t];
   for (long long int i = 0; i < SIZE(container.element_names); ++i) {
     if (container.element_names.at(i) == name) return i;
   }
-  raise << "unknown element " << name << " in container " << Type[t].name << '\n' << end();
+  raise << maybe(recipe_name) << "unknown element " << name << " in container " << Type[t].name << '\n' << end();
   return -1;
 }
 
@@ -147,7 +147,7 @@ recipe main [
 recipe main [
   x:number <- copy 1:number
 ]
-+warn: mixing variable names and numeric addresses in main
++warn: main: mixing variable names and numeric addresses
 
 :(scenario transform_names_warns_when_mixing_names_and_numeric_locations_2)
 % Hide_warnings = true;
@@ -155,14 +155,14 @@ recipe main [
   x:number <- copy 1
   1:number <- copy x:number
 ]
-+warn: mixing variable names and numeric addresses in main
++warn: main: mixing variable names and numeric addresses
 
 :(scenario transform_names_does_not_warn_when_mixing_names_and_raw_locations)
 % Hide_warnings = true;
 recipe main [
   x:number <- copy 1:number/raw
 ]
--warn: mixing variable names and numeric addresses in main
+-warn: main: mixing variable names and numeric addresses
 $warn: 0
 
 :(scenario transform_names_does_not_warn_when_mixing_names_and_literals)
@@ -170,7 +170,7 @@ $warn: 0
 recipe main [
   x:number <- copy 1
 ]
--warn: mixing variable names and numeric addresses in main
+-warn: main: mixing variable names and numeric addresses
 $warn: 0
 
 //:: Support element names for containers in 'get' and 'get-address'.
@@ -193,15 +193,15 @@ recipe main [
 if (inst.operation == Recipe_ordinal["get"]
     || inst.operation == Recipe_ordinal["get-address"]) {
   if (SIZE(inst.ingredients) != 2) {
-    raise << Recipe[r].name << ": exactly 2 ingredients expected in '" << inst.to_string() << "'\n" << end();
+    raise << maybe(Recipe[r].name) << "exactly 2 ingredients expected in '" << inst.to_string() << "'\n" << end();
     break;
   }
   if (!is_literal(inst.ingredients.at(1)))
-    raise << Recipe[r].name << ": expected ingredient 1 of " << (inst.operation == Recipe_ordinal["get"] ? "'get'" : "'get-address'") << " to have type 'offset'; got " << inst.ingredients.at(1).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "expected ingredient 1 of " << (inst.operation == Recipe_ordinal["get"] ? "'get'" : "'get-address'") << " to have type 'offset'; got " << inst.ingredients.at(1).original_string << '\n' << end();
   if (inst.ingredients.at(1).name.find_first_not_of("0123456789") != string::npos) {
     // since first non-address in base type must be a container, we don't have to canonize
-    type_ordinal base_type = skip_addresses(inst.ingredients.at(0).types);
-    inst.ingredients.at(1).set_value(find_element_name(base_type, inst.ingredients.at(1).name));
+    type_ordinal base_type = skip_addresses(inst.ingredients.at(0).types, Recipe[r].name);
+    inst.ingredients.at(1).set_value(find_element_name(base_type, inst.ingredients.at(1).name, Recipe[r].name));
     trace("name") << "element " << inst.ingredients.at(1).name << " of type " << Type[base_type].name << " is at offset " << no_scientific(inst.ingredients.at(1).value) << end();
   }
 }
@@ -233,14 +233,14 @@ recipe main [
 // convert variant names of exclusive containers
 if (inst.operation == Recipe_ordinal["maybe-convert"]) {
   if (SIZE(inst.ingredients) != 2) {
-    raise << Recipe[r].name << ": exactly 2 ingredients expected in '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(Recipe[r].name) << "exactly 2 ingredients expected in '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   assert(is_literal(inst.ingredients.at(1)));
   if (inst.ingredients.at(1).name.find_first_not_of("0123456789") != string::npos) {
     // since first non-address in base type must be an exclusive container, we don't have to canonize
-    type_ordinal base_type = skip_addresses(inst.ingredients.at(0).types);
-    inst.ingredients.at(1).set_value(find_element_name(base_type, inst.ingredients.at(1).name));
+    type_ordinal base_type = skip_addresses(inst.ingredients.at(0).types, Recipe[r].name);
+    inst.ingredients.at(1).set_value(find_element_name(base_type, inst.ingredients.at(1).name, Recipe[r].name));
     trace("name") << "variant " << inst.ingredients.at(1).name << " of type " << Type[base_type].name << " has tag " << no_scientific(inst.ingredients.at(1).value) << end();
   }
 }
diff --git a/043new.cc b/043new.cc
index a99296f2..d6761dad 100644
--- a/043new.cc
+++ b/043new.cc
@@ -34,13 +34,13 @@ if (inst.operation == Recipe_ordinal["new"]) {
   // End NEW Transform Special-cases
   // first arg must be of type 'type'
   if (inst.ingredients.empty())
-    raise << Recipe[r].name << ": 'new' expects one or two ingredients\n" << end();
+    raise << maybe(Recipe[r].name) << "'new' expects one or two ingredients\n" << end();
   if (inst.ingredients.at(0).properties.empty()
       || inst.ingredients.at(0).properties.at(0).second.empty()
       || inst.ingredients.at(0).properties.at(0).second.at(0) != "type")
-    raise << Recipe[r].name << ": first ingredient of 'new' should be a type, but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(Recipe[r].name) << "first ingredient of 'new' should be a type, but got " << inst.ingredients.at(0).original_string << '\n' << end();
   if (Type_ordinal.find(inst.ingredients.at(0).name) == Type_ordinal.end())
-    raise << Recipe[r].name << ": unknown type " << inst.ingredients.at(0).name << '\n' << end();
+    raise << maybe(Recipe[r].name) << "unknown type " << inst.ingredients.at(0).name << '\n' << end();
   inst.ingredients.at(0).set_value(Type_ordinal[inst.ingredients.at(0).name]);
   trace(Primitive_recipe_depth, "new") << inst.ingredients.at(0).name << " -> " << inst.ingredients.at(0).name << end();
   end_new_transform:;
@@ -56,11 +56,11 @@ Recipe_ordinal["new"] = NEW;
 :(before "End Primitive Recipe Implementations")
 case NEW: {
   if (ingredients.empty() || SIZE(ingredients) > 2) {
-    raise << current_recipe_name() << ": 'new' requires one or two ingredients, but got " << current_instruction().to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "'new' requires one or two ingredients, but got " << current_instruction().to_string() << '\n' << end();
     break;
   }
   if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'new' should be a type, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'new' should be a type, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   // compute the space we need
@@ -216,17 +216,17 @@ Recipe_ordinal["abandon"] = ABANDON;
 :(before "End Primitive Recipe Implementations")
 case ABANDON: {
   if (SIZE(ingredients) != 1) {
-    raise << current_recipe_name() << ": 'abandon' requires one ingredient, but got '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "'abandon' requires one ingredient, but got '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'abandon' should be an address, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'abandon' should be an address, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   long long int address = ingredients.at(0).at(0);
   reagent types = canonize(current_instruction().ingredients.at(0));
   if (types.types.empty() || types.types.at(0) != Type_ordinal["address"]) {
-    raise << current_recipe_name() << ": first ingredient of 'abandon' should be an address, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'abandon' should be an address, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   reagent target_type = lookup_memory(types);
@@ -253,7 +253,7 @@ if (Free_list[size]) {
   Free_list[size] = Memory[result];
   for (long long int curr = result+1; curr < result+size; ++curr) {
     if (Memory[curr] != 0) {
-      raise << current_recipe_name() << ": memory in free list was not zeroed out: " << curr << '/' << result << "; somebody wrote to us after free!!!\n" << end();
+      raise << maybe(current_recipe_name()) << "memory in free list was not zeroed out: " << curr << '/' << result << "; somebody wrote to us after free!!!\n" << end();
       break;  // always fatal
     }
   }
diff --git a/044space.cc b/044space.cc
index a9251364..59b292a5 100644
--- a/044space.cc
+++ b/044space.cc
@@ -138,7 +138,7 @@ if (curr.name == "new-default-space") {
   }
 :(after "void write_memory(reagent x, vector<double> data)")
   if (x.name == "number-of-locals") {
-    raise << current_recipe_name() << ": can't write to special name 'number-of-locals'\n" << end();
+    raise << maybe(current_recipe_name()) << "can't write to special name 'number-of-locals'\n" << end();
     return;
   }
 
@@ -212,7 +212,7 @@ long long int address(long long int offset, long long int base) {
 :(after "void write_memory(reagent x, vector<double> data)")
   if (x.name == "default-space") {
     if (!scalar(data))
-      raise << current_recipe_name() << ": 'default-space' should be of type address:array:location, but tried to write " << to_string(data) << '\n' << end();
+      raise << maybe(current_recipe_name()) << "'default-space' should be of type address:array:location, but tried to write " << to_string(data) << '\n' << end();
     Current_routine->calls.front().default_space = data.at(0);
     return;
   }
diff --git a/045space_surround.cc b/045space_surround.cc
index 68d23c93..94a717a0 100644
--- a/045space_surround.cc
+++ b/045space_surround.cc
@@ -42,7 +42,7 @@ long long int space_index(const reagent& x) {
   for (long long int i = /*skip name:type*/1; i < SIZE(x.properties); ++i) {
     if (x.properties.at(i).first == "space") {
       if (SIZE(x.properties.at(i).second) != 1)
-        raise << current_recipe_name() << ": /space metadata should take exactly one value in " << x.original_string << '\n' << end();
+        raise << maybe(current_recipe_name()) << "/space metadata should take exactly one value in " << x.original_string << '\n' << end();
       return to_integer(x.properties.at(i).second.at(0));
     }
   }
diff --git a/047global.cc b/047global.cc
index 90646f49..00e8ff15 100644
--- a/047global.cc
+++ b/047global.cc
@@ -32,7 +32,7 @@ global_space = 0;
 :(after "void write_memory(reagent x, vector<double> data)")
   if (x.name == "global-space") {
     if (!scalar(data))
-      raise << current_recipe_name() << ": 'global-space' should be of type address:array:location, but tried to write " << to_string(data) << '\n' << end();
+      raise << maybe(current_recipe_name()) << "'global-space' should be of type address:array:location, but tried to write " << to_string(data) << '\n' << end();
     if (Current_routine->global_space)
       raise << "routine already has a global-space; you can't over-write your globals" << end();
     Current_routine->global_space = data.at(0);
diff --git a/048check_type_by_name.cc b/048check_type_by_name.cc
index e4b4f6d0..26920057 100644
--- a/048check_type_by_name.cc
+++ b/048check_type_by_name.cc
@@ -12,7 +12,7 @@ recipe main [
   x:number <- copy 1
   x:boolean <- copy 1
 ]
-+warn: x used with multiple types in main
++warn: main: x used with multiple types
 
 :(after "int main")
   Transform.push_back(check_types_by_name);
@@ -42,7 +42,7 @@ void check_metadata(map<string, vector<type_ordinal> >& metadata, const reagent&
   if (metadata.find(x.name) == metadata.end())
     metadata[x.name] = x.types;
   if (metadata[x.name] != x.types)
-    raise << x.name << " used with multiple types in " << Recipe[r].name << '\n' << end();
+    raise << maybe(Recipe[r].name) << "" << x.name << " used with multiple types\n" << end();
 }
 
 :(scenario transform_fills_in_missing_types)
@@ -80,7 +80,7 @@ recipe main [
   x <- copy 1
   x:number <- copy 2
 ]
-+warn: missing type for x in 'x <- copy 1'
++warn: main: missing type for x in 'x <- copy 1'
 
 :(scenario typo_in_address_type_warns)
 % Hide_warnings = true;
diff --git a/050scenario.cc b/050scenario.cc
index 5378ff5d..65e161b3 100644
--- a/050scenario.cc
+++ b/050scenario.cc
@@ -560,16 +560,16 @@ Recipe_ordinal["check-trace-count-for-label"] = CHECK_TRACE_COUNT_FOR_LABEL;
 case CHECK_TRACE_COUNT_FOR_LABEL: {
   if (!Passed) break;
   if (SIZE(current_instruction().ingredients) != 2) {
-    raise << current_recipe_name() << ": 'check-trace-for-label' requires exactly two ingredients, but got '" << current_instruction().to_string() << "'\n" << end();
+    raise << maybe(current_recipe_name()) << "'check-trace-for-label' requires exactly two ingredients, but got '" << current_instruction().to_string() << "'\n" << end();
     break;
   }
   if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'check-trace-for-label' should be a number (count), but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'check-trace-for-label' should be a number (count), but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   long long int expected_count = ingredients.at(0).at(0);
   if (!is_literal_string(current_instruction().ingredients.at(1))) {
-    raise << current_recipe_name() << ": second ingredient of 'check-trace-for-label' should be a literal string (label), but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "second ingredient of 'check-trace-for-label' should be a literal string (label), but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
     break;
   }
   string label = current_instruction().ingredients.at(1).name;
@@ -577,13 +577,13 @@ case CHECK_TRACE_COUNT_FOR_LABEL: {
   if (count != expected_count) {
     if (Current_scenario && !Scenario_testing_scenario) {
       // genuine test in a mu file
-      raise << "\nF - " << Current_scenario->name << ": " << current_recipe_name() << ": expected " << expected_count << " lines in trace with label " << label << " in trace: ";
+      raise << "\nF - " << Current_scenario->name << ": " << maybe(current_recipe_name()) << "expected " << expected_count << " lines in trace with label " << label << " in trace: ";
       DUMP(label);
       raise;
     }
     else {
       // just testing scenario support
-      raise << current_recipe_name() << ": expected " << expected_count << " lines in trace with label " << label << " in trace\n" << end();
+      raise << maybe(current_recipe_name()) << "expected " << expected_count << " lines in trace with label " << label << " in trace\n" << end();
     }
     if (!Scenario_testing_scenario) {
       Passed = false;
diff --git a/053continuation.cc b/053continuation.cc
index 769e09e8..42f32f6d 100644
--- a/053continuation.cc
+++ b/053continuation.cc
@@ -41,7 +41,7 @@ Recipe_ordinal["continue-from"] = CONTINUE_FROM;
 :(before "End Primitive Recipe Implementations")
 case CONTINUE_FROM: {
   if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'continue-from' should be a continuation id generated by 'current-continuation', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'continue-from' should be a continuation id generated by 'current-continuation', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   long long int c = ingredients.at(0).at(0);
@@ -198,7 +198,7 @@ case REPLY_DELIMITED_CONTINUATION: {
   call_stack::iterator find_reset(call_stack& c);  // manual prototype containing '::'
   call_stack::iterator reset = find_reset(Current_routine->calls);
   if (reset == Current_routine->calls.end()) {
-    raise << current_recipe_name() << ": couldn't find a 'reset' call to jump out to\n" << end();
+    raise << maybe(current_recipe_name()) << "couldn't find a 'reset' call to jump out to\n" << end();
     break;
   }
   Delimited_continuation[Next_delimited_continuation_id] = call_stack(Current_routine->calls.begin(), reset);
@@ -228,7 +228,7 @@ call_stack::iterator find_reset(call_stack& c) {
     // copy multiple calls on to current call stack
     assert(scalar(ingredients.at(0)));
     if (Delimited_continuation.find(ingredients.at(0).at(0)) == Delimited_continuation.end()) {
-      raise << current_recipe_name() << ": no such delimited continuation " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+      raise << maybe(current_recipe_name()) << "no such delimited continuation " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     }
     const call_stack& new_calls = Delimited_continuation[ingredients.at(0).at(0)];
     for (call_stack::const_reverse_iterator p = new_calls.rbegin(); p != new_calls.rend(); ++p)
diff --git a/064random.cc b/064random.cc
index bd171132..07667cc2 100644
--- a/064random.cc
+++ b/064random.cc
@@ -28,11 +28,11 @@ Recipe_ordinal["round"] = ROUND;
 :(before "End Primitive Recipe Implementations")
 case ROUND: {
   if (SIZE(ingredients) != 1) {
-    raise << current_recipe_name() << ": 'round' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "'round' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
     break;
   }
   if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'round' should be a number, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'round' should be a number, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   products.resize(1);
diff --git a/070display.cc b/070display.cc
index 8c02bc57..1f42e5ba 100644
--- a/070display.cc
+++ b/070display.cc
@@ -83,18 +83,18 @@ case PRINT_CHARACTER_TO_DISPLAY: {
   long long int height = (h >= 0) ? h : 0;
   long long int width = (w >= 0) ? w : 0;
   if (ingredients.empty()) {
-    raise << current_recipe_name() << ": 'print-character-to-display' requires at least one ingredient, but got " << current_instruction().to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "'print-character-to-display' requires at least one ingredient, but got " << current_instruction().to_string() << '\n' << end();
     break;
   }
   if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'print-character-to-display' should be a character, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'print-character-to-display' should be a character, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   long long int c = ingredients.at(0).at(0);
   int color = TB_BLACK;
   if (SIZE(ingredients) > 1) {
     if (!scalar(ingredients.at(1))) {
-      raise << current_recipe_name() << ": second ingredient of 'print-character-to-display' should be a foreground color number, but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
+      raise << maybe(current_recipe_name()) << "second ingredient of 'print-character-to-display' should be a foreground color number, but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
       break;
     }
     color = ingredients.at(1).at(0);
@@ -102,7 +102,7 @@ case PRINT_CHARACTER_TO_DISPLAY: {
   int bg_color = TB_BLACK;
   if (SIZE(ingredients) > 2) {
     if (!scalar(ingredients.at(2))) {
-      raise << current_recipe_name() << ": third ingredient of 'print-character-to-display' should be a background color number, but got " << current_instruction().ingredients.at(2).original_string << '\n' << end();
+      raise << maybe(current_recipe_name()) << "third ingredient of 'print-character-to-display' should be a background color number, but got " << current_instruction().ingredients.at(2).original_string << '\n' << end();
       break;
     }
     bg_color = ingredients.at(2).at(0);
@@ -154,16 +154,16 @@ Recipe_ordinal["move-cursor-on-display"] = MOVE_CURSOR_ON_DISPLAY;
 :(before "End Primitive Recipe Implementations")
 case MOVE_CURSOR_ON_DISPLAY: {
   if (SIZE(ingredients) != 2) {
-    raise << current_recipe_name() << ": 'move-cursor-on-display' requires two ingredients, but got " << current_instruction().to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "'move-cursor-on-display' requires two ingredients, but got " << current_instruction().to_string() << '\n' << end();
     break;
   }
   if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'move-cursor-on-display' should be a row number, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'move-cursor-on-display' should be a row number, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   Display_row = ingredients.at(0).at(0);
   if (!scalar(ingredients.at(1))) {
-    raise << current_recipe_name() << ": second ingredient of 'move-cursor-on-display' should be a column number, but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "second ingredient of 'move-cursor-on-display' should be a column number, but got " << current_instruction().ingredients.at(1).original_string << '\n' << end();
     break;
   }
   Display_column = ingredients.at(1).at(0);
diff --git a/072scenario_screen.cc b/072scenario_screen.cc
index 29ae4c5d..732a2999 100644
--- a/072scenario_screen.cc
+++ b/072scenario_screen.cc
@@ -191,13 +191,13 @@ struct raw_string_stream {
 void check_screen(const string& expected_contents, const int color) {
   assert(!Current_routine->calls.front().default_space);  // not supported
   long long int screen_location = Memory[SCREEN];
-  int data_offset = find_element_name(Type_ordinal["screen"], "data");
+  int data_offset = find_element_name(Type_ordinal["screen"], "data", "");
   assert(data_offset >= 0);
   long long int screen_data_location = screen_location+data_offset;  // type: address:array:character
   long long int screen_data_start = Memory[screen_data_location];  // type: array:character
-  int width_offset = find_element_name(Type_ordinal["screen"], "num-columns");
+  int width_offset = find_element_name(Type_ordinal["screen"], "num-columns", "");
   long long int screen_width = Memory[screen_location+width_offset];
-  int height_offset = find_element_name(Type_ordinal["screen"], "num-rows");
+  int height_offset = find_element_name(Type_ordinal["screen"], "num-rows", "");
   long long int screen_height = Memory[screen_location+height_offset];
   raw_string_stream cursor(expected_contents);
   // todo: too-long expected_contents should fail
@@ -245,14 +245,16 @@ void check_screen(const string& expected_contents, const int color) {
         actual_pretty[0] = ' ', actual_pretty[1] = '(', actual_pretty[2] = '\'', actual_pretty[3] = static_cast<unsigned char>(Memory[addr]), actual_pretty[4] = '\'', actual_pretty[5] = ')', actual_pretty[6] = '\0';
       }
 
+      ostringstream color_phrase;
+      if (color != -1) color_phrase << " in color " << color;
       if (Current_scenario && !Scenario_testing_scenario) {
         // genuine test in a mu file
-        raise << "\nF - " << Current_scenario->name << ": expected screen location (" << row << ", " << column << ") to contain " << curr << expected_pretty << " instead of " << no_scientific(Memory[addr]) << actual_pretty << '\n' << end();
+        raise << "\nF - " << Current_scenario->name << ": expected screen location (" << row << ", " << column << ") to contain " << curr << expected_pretty << color_phrase.str() << " instead of " << no_scientific(Memory[addr]) << actual_pretty << '\n' << end();
         dump_screen();
       }
       else {
         // just testing check_screen
-        raise << "expected screen location (" << row << ", " << column << ") to contain " << curr << expected_pretty << " instead of " << no_scientific(Memory[addr]) << actual_pretty << '\n' << end();
+        raise << "expected screen location (" << row << ", " << column << ") to contain " << curr << expected_pretty << color_phrase.str() << " instead of " << no_scientific(Memory[addr]) << actual_pretty << '\n' << end();
       }
       if (!Scenario_testing_scenario) {
         Passed = false;
@@ -320,11 +322,11 @@ case _DUMP_SCREEN: {
 void dump_screen() {
   assert(!Current_routine->calls.front().default_space);  // not supported
   long long int screen_location = Memory[SCREEN];
-  int width_offset = find_element_name(Type_ordinal["screen"], "num-columns");
+  int width_offset = find_element_name(Type_ordinal["screen"], "num-columns", "");
   long long int screen_width = Memory[screen_location+width_offset];
-  int height_offset = find_element_name(Type_ordinal["screen"], "num-rows");
+  int height_offset = find_element_name(Type_ordinal["screen"], "num-rows", "");
   long long int screen_height = Memory[screen_location+height_offset];
-  int data_offset = find_element_name(Type_ordinal["screen"], "data");
+  int data_offset = find_element_name(Type_ordinal["screen"], "data", "");
   assert(data_offset >= 0);
   long long int screen_data_location = screen_location+data_offset;  // type: address:array:character
   long long int screen_data_start = Memory[screen_data_location];  // type: array:character
diff --git a/081run_interactive.cc b/081run_interactive.cc
index dd3fc5c3..eccf2d07 100644
--- a/081run_interactive.cc
+++ b/081run_interactive.cc
@@ -29,11 +29,11 @@ Recipe_ordinal["run-interactive"] = RUN_INTERACTIVE;
 :(before "End Primitive Recipe Implementations")
 case RUN_INTERACTIVE: {
   if (SIZE(ingredients) != 1) {
-    raise << current_recipe_name() << ": 'run-interactive' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "'run-interactive' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
     break;
   }
   if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'run-interactive' should be a string, but got " << current_instruction().ingredients.at(0).to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'run-interactive' should be a string, but got " << current_instruction().ingredients.at(0).to_string() << '\n' << end();
     break;
   }
   bool new_code_pushed_to_stack = run_interactive(ingredients.at(0).at(0));
@@ -140,6 +140,10 @@ load(string(
 transform_all();
 recently_added_recipes.clear();
 
+//: adjust warnings in the sandbox
+:(after "string maybe(string s)")
+  if (s == "interactive") return "";
+
 :(scenario run_interactive_comments)
 recipe main [
   1:address:array:character <- new [# ab
@@ -342,11 +346,11 @@ Recipe_ordinal["reload"] = RELOAD;
 :(before "End Primitive Recipe Implementations")
 case RELOAD: {
   if (SIZE(ingredients) != 1) {
-    raise << current_recipe_name() << ": 'reload' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "'reload' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
     break;
   }
   if (!scalar(ingredients.at(0))) {
-    raise << current_recipe_name() << ": first ingredient of 'reload' should be a literal string, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'reload' should be a literal string, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end();
     break;
   }
   // clear any containers in advance
diff --git a/082persist.cc b/082persist.cc
index 853ccb62..40241eb2 100644
--- a/082persist.cc
+++ b/082persist.cc
@@ -9,7 +9,7 @@ Recipe_ordinal["restore"] = RESTORE;
 :(before "End Primitive Recipe Implementations")
 case RESTORE: {
   if (SIZE(ingredients) != 1) {
-    raise << current_recipe_name() << ": 'restore' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "'restore' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end();
     break;
   }
   string filename;
@@ -20,7 +20,7 @@ case RESTORE: {
     filename = read_mu_string(ingredients.at(0).at(0));
   }
   else {
-    raise << current_recipe_name() << ": first ingredient of 'restore' should be a string, but got " << current_instruction().ingredients.at(0).to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'restore' should be a string, but got " << current_instruction().ingredients.at(0).to_string() << '\n' << end();
     break;
   }
   if (Current_scenario) {
@@ -62,7 +62,7 @@ Recipe_ordinal["save"] = SAVE;
 :(before "End Primitive Recipe Implementations")
 case SAVE: {
   if (SIZE(ingredients) != 2) {
-    raise << current_recipe_name() << ": 'save' requires exactly two ingredients, but got " << current_instruction().to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "'save' requires exactly two ingredients, but got " << current_instruction().to_string() << '\n' << end();
     break;
   }
   if (Current_scenario) break;  // do nothing in tests
@@ -74,11 +74,11 @@ case SAVE: {
     filename = read_mu_string(ingredients.at(0).at(0));
   }
   else {
-    raise << current_recipe_name() << ": first ingredient of 'save' should be a string, but got " << current_instruction().ingredients.at(0).to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "first ingredient of 'save' should be a string, but got " << current_instruction().ingredients.at(0).to_string() << '\n' << end();
     break;
   }
   if (!scalar(ingredients.at(1))) {
-    raise << current_recipe_name() << ": second ingredient of 'save' should be an address:array:character, but got " << current_instruction().ingredients.at(1).to_string() << '\n' << end();
+    raise << maybe(current_recipe_name()) << "second ingredient of 'save' should be an address:array:character, but got " << current_instruction().ingredients.at(1).to_string() << '\n' << end();
     break;
   }
   ofstream fout(("lesson/"+filename).c_str());
diff --git a/edit/010-warnings.mu b/edit/010-warnings.mu
index 6c93a95c..10f05325 100644
--- a/edit/010-warnings.mu
+++ b/edit/010-warnings.mu
@@ -96,7 +96,7 @@ recipe foo [
     .recipe foo [                                      ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
     .  get 123:number, foo:offset                      ┊                                                 .
     .]                                                 ┊                                                 .
-    .unknown element foo in container number           ┊                                                 .
+    .foo: unknown element foo in container number      ┊                                                 .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .
     .                                                  ┊                                                 .
   ]
@@ -106,7 +106,7 @@ recipe foo [
     .                                                                                                    .
     .                                                                                                    .
     .                                                                                                    .
-    .unknown element foo in container number                                                             .
+    .foo: unknown element foo in container number                                                        .
     .                                                                                                    .
   ]
 ]
@@ -132,7 +132,7 @@ recipe foo [
     .recipe foo [                                      ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
     .  x <- copy 0                                     ┊                                                 .
     .]                                                 ┊                                                 .
-    .missing type for x in 'x <- copy 0'               ┊                                                 .
+    .foo: missing type for x in 'x <- copy 0'          ┊                                                 .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .
     .                                                  ┊                                                 .
   ]
@@ -250,7 +250,7 @@ recipe foo [
     .recipe foo [                                      ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
     .  x:number <- copy y:number                       ┊                                                 .
     .]                                                 ┊                                                 .
-    .use before set: y in foo                          ┊                                                 .
+    .foo: use before set: y                            ┊                                                 .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .
     .                                                  ┊                                                 .
   ]
@@ -267,7 +267,7 @@ recipe foo [
     .recipe foo [                                      ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
     .  x:number <- copy y:number                       ┊                                                 .
     .]                                                 ┊                                                 .
-    .use before set: y in foo                          ┊                                                 .
+    .foo: use before set: y                            ┊                                                 .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .
     .                                                  ┊                                                 .
   ]