diff --git a/Makefile.am b/Makefile.am
index 6693f4649525cde8cc8f0dc75d4a56f3c6fba521..2331e532af581502d606ca4c4ea12720b5efe09c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -159,6 +159,7 @@ test_cases = \
 	tests/extensions/duplicate/execute.svtest \
 	tests/extensions/duplicate/execute-vnd.svtest \
 	tests/extensions/metadata/execute.svtest \
+	tests/extensions/metadata/errors.svtest \
 	tests/extensions/vnd.dovecot/debug/execute.svtest \
 	tests/deprecated/notify/basic.svtest \
 	tests/deprecated/notify/mailto.svtest \
diff --git a/src/lib-sieve/plugins/metadata/tst-metadataexists.c b/src/lib-sieve/plugins/metadata/tst-metadataexists.c
index 58808354a684c637f6b2f39ffed92a9864a83b66..99b7dd0356e427eed2147a20758c154dcccda0c4 100644
--- a/src/lib-sieve/plugins/metadata/tst-metadataexists.c
+++ b/src/lib-sieve/plugins/metadata/tst-metadataexists.c
@@ -104,10 +104,41 @@ const struct sieve_operation_def servermetadataexists_operation = {
  * Test validation
  */
 
+struct _validate_context {
+	struct sieve_validator *valdtr;
+	struct sieve_command *tst;
+};
+
+static int tst_metadataexists_annotation_validate
+(void *context, struct sieve_ast_argument *arg)
+{
+	struct _validate_context *valctx =
+		(struct _validate_context *)context;
+
+	if ( sieve_argument_is_string_literal(arg) ) {
+		const char *aname = sieve_ast_strlist_strc(arg);
+		const char *error;
+
+		if ( !imap_metadata_verify_entry_name(aname, &error) ) {
+			char *lcerror = t_strdup_noconst(error);
+			lcerror[0] = i_tolower(lcerror[0]);
+			sieve_argument_validate_warning
+				(valctx->valdtr, arg, "%s test: "
+					"specified annotation name `%s' is invalid: %s",
+					sieve_command_identifier(valctx->tst),
+					str_sanitize(aname, 256), lcerror);
+		}
+	}
+
+	return TRUE; /* Can't check at compile time */
+}
+
 static bool tst_metadataexists_validate
 (struct sieve_validator *valdtr, struct sieve_command *tst)
 {
 	struct sieve_ast_argument *arg = tst->first_positional;
+	struct sieve_ast_argument *aarg; 
+	struct _validate_context valctx;
 	unsigned int arg_index = 1;
 
 	if ( sieve_command_is(tst, metadataexists_test) ) {
@@ -127,7 +158,16 @@ static bool tst_metadataexists_validate
 		return FALSE;
 	}
 
-	return sieve_validator_argument_activate(valdtr, tst, arg, FALSE);
+	if ( !sieve_validator_argument_activate(valdtr, tst, arg, FALSE) )
+		return FALSE;
+
+	aarg = arg;
+	memset(&valctx, 0, sizeof(valctx));
+	valctx.valdtr = valdtr;
+	valctx.tst = tst;
+
+	return sieve_ast_stringlist_map
+		(&aarg, (void*)&valctx, tst_metadataexists_annotation_validate);
 }
 
 /*
@@ -232,7 +272,8 @@ static int tst_metadataexists_check_annotations
 				"specified annotation name `%s' is invalid: %s",
 				(mailbox != NULL ? "metadataexists" : "servermetadataexists"),
 				str_sanitize(str_c(aname), 256), _lc_error(error));
-			continue;
+			all_exist = FALSE;
+			break;;
 		}
 
 		ret = imap_metadata_get(imtrans, str_c(aname), &avalue);
diff --git a/tests/extensions/metadata/errors.svtest b/tests/extensions/metadata/errors.svtest
new file mode 100644
index 0000000000000000000000000000000000000000..e0cffaafc5f67a518556bd72b0d5ec9044d13c01
--- /dev/null
+++ b/tests/extensions/metadata/errors.svtest
@@ -0,0 +1,18 @@
+require "vnd.dovecot.testsuite";
+
+require "relational";
+require "comparator-i;ascii-numeric";
+
+/*
+ * Invalid syntax
+ */
+
+test "Invalid Syntax" {
+        if test_script_compile "errors/syntax.sieve" {
+                test_fail "compile should have failed";
+        }
+
+        if not test_error :count "eq" :comparator "i;ascii-numeric" "27" {
+                test_fail "wrong number of errors reported";
+        }
+}
diff --git a/tests/extensions/metadata/errors/syntax.sieve b/tests/extensions/metadata/errors/syntax.sieve
new file mode 100644
index 0000000000000000000000000000000000000000..4b488d13658f79ad213815f880137c37ed98ba60
--- /dev/null
+++ b/tests/extensions/metadata/errors/syntax.sieve
@@ -0,0 +1,48 @@
+require "mboxmetadata";
+require "servermetadata";
+
+# 1-4: Used as a command
+metadata;
+metadataexists;
+servermetadata;
+servermetadataexists;
+
+# 5-8: Used with no argument
+if metadata {}
+if metadataexists {}
+if servermetadata {}
+if servermetadataexists {}
+
+# 9-10: Used with one string argument
+if metadata "frop" { }
+if servermetadata "frop" { }
+if metadataexists "frop" { }
+
+# Used with one number argument
+if metadata 13123123 { }
+if servermetadata 123123 { }
+if metadataexists 123123 { }
+if servermetadataexists 123123 {}
+
+# Used with one string list argument
+if metadata ["frop"] { }
+if servermetadata ["frop"] { }
+if metadataexists ["frop"] { }
+
+# Used with unknown tag
+if metadata :frop "frop" { }
+if servermetadata :frop "frop" { }
+if metadataexists :frop "frop" { }
+if servermetadataexists :frop "frop" {}
+
+# Invalid arguments
+if metadata "/private/frop" "friep" {}
+if servermetadata "INBOX" "/private/frop" "friep" {}
+if metadataexists 23 "/private/frop" {}
+if servermetadataexists "INBOX" "/private/frop" {}
+
+# Invalid annotations
+if metadata "INBOX" "frop" "friep" {}
+if servermetadata "frop" "friep" {}
+if metadataexists "INBOX" ["/private/frop", "/friep"] { }
+if servermetadataexists ["/private/frop", "/friep", "/private/friep"] { }
diff --git a/tests/extensions/metadata/execute.svtest b/tests/extensions/metadata/execute.svtest
index 0a218092a52b731f26c310f02248ca243e15ed6f..e3a2b70c87863f9c50eb0c9a0453868c6cb28e2e 100644
--- a/tests/extensions/metadata/execute.svtest
+++ b/tests/extensions/metadata/execute.svtest
@@ -35,6 +35,13 @@ test "MetadataExists - All exist" {
 	}
 }
 
+test "MetadataExists - Invalid" {
+	if metadataexists "INBOX"
+		["/shared/frop", "/friep", "/private/frml"] {
+		test_fail "metadataexists accepted invalid annotation name";
+	}
+}
+
 test "Metadata" {
 	if not metadata :is "INBOX" "/private/frop" "FROP!" {
 		test_fail "invalid metadata value for /private/frop";
@@ -58,6 +65,12 @@ test "Metadata" {
 	}
 }
 
+test "Metadata - Invalid" {
+	if metadata :contains "INBOX" "/frop" "" {
+		test_fail "erroneously found a value for \"/frop\"";
+	}
+}
+
 test "ServermetadataExists - None exist" {
 	if servermetadataexists "/private/frop" {
 		test_fail "servermetadataexists confirms existence of unknown annotation";
@@ -86,7 +99,14 @@ test "ServermetadataExists - One exists" {
 test "ServermetadataExists - All exist" {
 	if not servermetadataexists
 		["/private/frop", "/private/friep", "/private/frml"] {
-		test_fail "metadataexists fails to recognize annotations";
+		test_fail "servermetadataexists fails to recognize annotations";
+	}
+}
+
+test "ServermetadataExists - Invalid" {
+	if servermetadataexists
+		["frop", "/private/friep", "/private/frml"] {
+		test_fail "servermetadataexists accepted invalid annotation name";
 	}
 }
 
@@ -112,3 +132,10 @@ test "Servermetadata" {
 		test_fail "unexpected match for /private/frml";
 	}
 }
+
+test "Servermetadata - Invalid" {
+	if servermetadata :contains "/frop" "" {
+		test_fail "erroneously found a value for \"/frop\"";
+	}
+}
+