diff --git a/README.md b/README.md
index a5102eb8..5e73ffee 100644
--- a/README.md
+++ b/README.md
@@ -389,6 +389,7 @@ The following validators are built in:
 - `MinimumNArgs(int)` - the command will report an error if there are not at least N positional args.
 - `MaximumNArgs(int)` - the command will report an error if there are more than N positional args.
 - `ExactArgs(int)` - the command will report an error if there are not exactly N positional args.
+- `ExactValidArgs(int)` = the command will report and error if there are not exactly N positional args OR if there are any positional args that are not in the `ValidArgs` field of `Command`
 - `RangeArgs(min, max)` - the command will report an error if the number of args is not between the minimum and maximum number of expected args.
 
 An example of setting the custom validator:
diff --git a/args.go b/args.go
index a5d8a927..c4d820b8 100644
--- a/args.go
+++ b/args.go
@@ -78,6 +78,18 @@ func ExactArgs(n int) PositionalArgs {
 	}
 }
 
+// ExactValidArgs returns an error if
+// there are not exactly N positional args OR
+// there are any positional args that are not in the `ValidArgs` field of `Command`
+func ExactValidArgs(n int) PositionalArgs {
+	return func(cmd *Command, args []string) error {
+		if err := ExactArgs(n)(cmd, args); err != nil {
+			return err
+		}
+		return OnlyValidArgs(cmd, args)
+	}
+}
+
 // RangeArgs returns an error if the number of args is not within the expected range.
 func RangeArgs(min int, max int) PositionalArgs {
 	return func(cmd *Command, args []string) error {
diff --git a/args_test.go b/args_test.go
index d797b6f5..c81b212e 100644
--- a/args_test.go
+++ b/args_test.go
@@ -158,6 +158,52 @@ func TestExactArgsWithInvalidCount(t *testing.T) {
 	}
 }
 
+func TestExactValidArgs(t *testing.T) {
+	c := &Command{Use: "c", Args: ExactValidArgs(3), ValidArgs: []string{"a", "b", "c"}, Run: emptyRun}
+	output, err := executeCommand(c, "a", "b", "c")
+	if output != "" {
+		t.Errorf("Unexpected output: %v", output)
+	}
+	if err != nil {
+		t.Errorf("Unexpected error: %v", err)
+	}
+}
+
+func TestExactValidArgsWithInvalidCount(t *testing.T) {
+	c := &Command{Use: "c", Args: ExactValidArgs(2), Run: emptyRun}
+	_, err := executeCommand(c, "a", "b", "c")
+
+	if err == nil {
+		t.Fatal("Expected an error")
+	}
+
+	got := err.Error()
+	expected := "accepts 2 arg(s), received 3"
+	if got != expected {
+		t.Fatalf("Expected %q, got %q", expected, got)
+	}
+}
+
+func TestExactValidArgsWithInvalidArgs(t *testing.T) {
+	c := &Command{
+		Use:       "c",
+		Args:      ExactValidArgs(1),
+		ValidArgs: []string{"one", "two"},
+		Run:       emptyRun,
+	}
+
+	_, err := executeCommand(c, "three")
+	if err == nil {
+		t.Fatal("Expected an error")
+	}
+
+	got := err.Error()
+	expected := `invalid argument "three" for "c"`
+	if got != expected {
+		t.Errorf("Expected: %q, got: %q", expected, got)
+	}
+}
+
 func TestRangeArgs(t *testing.T) {
 	c := &Command{Use: "c", Args: RangeArgs(2, 4), Run: emptyRun}
 	output, err := executeCommand(c, "a", "b", "c")