diff --git a/doc/iallocator.rst b/doc/iallocator.rst
index 582f00a2b69591c106d2101f5cabf887cb765ae1..6ecd62696d617e704a8cc44bc7a90ae52c6dc664 100644
--- a/doc/iallocator.rst
+++ b/doc/iallocator.rst
@@ -205,19 +205,19 @@ in the ``request`` dictionary:
   name
     the name of the instance; if the request is a realocation, then this
     name will be found in the list of instances (see below), otherwise
-    is the FQDN of the new instance
+    is the FQDN of the new instance; type *string*
 
   required_nodes
     how many nodes should the algorithm return; while this information
     can be deduced from the instace's disk template, it's better if
     this computation is left to Ganeti as then allocator scripts are
-    less sensitive to changes to the disk templates
+    less sensitive to changes to the disk templates; type *integer*
 
   disk_space_total
     the total disk space that will be used by this instance on the
     (new) nodes; again, this information can be computed from the list
     of instance disks and its template type, but Ganeti is better
-    suited to compute it
+    suited to compute it; type *integer*
 
 .. pyassert::
 
@@ -274,13 +274,13 @@ Relocation:
   relocate_from
      a list of nodes to move the instance away from (note that with
      Ganeti 2.0, this list will always contain a single node, the
-     current secondary of the instance)
+     current secondary of the instance); type *list of strings*
 
 As for ``multi-relocate``, it needs the three following request
 arguments:
 
   instances
-    a list of instance names to relocate
+    a list of instance names to relocate; type *list of strings*
 
   reloc_mode
     a string indicating the relocation mode; there are three possible
@@ -292,13 +292,13 @@ arguments:
     this argument is only accepted when ``reloc_mode``, as explained
     above, is *change_group*; if present, it must either be the empty
     list, or contain a list of group UUIDs that should be considered for
-    relocating instances to
+    relocating instances to; type *list of strings*
 
 Finally, in the case of multi-evacuate, there's one single request
 argument (in addition to ``type``):
 
   evac_nodes
-    the names of the nodes to be evacuated
+    the names of the nodes to be evacuated; type *list of strings*
 
 Response message
 ~~~~~~~~~~~~~~~~
diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index dab6f26bc467ee3348c948180ce176a192cfe4a9..16dde30a9f80fc2ce30027c7f5adbdae7295e06f 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -12020,11 +12020,13 @@ class IAllocator(object):
     self.success = self.info = self.result = None
 
     try:
-      (fn, keyset, self._result_check) = self._MODE_DATA[self.mode]
+      (fn, keydata, self._result_check) = self._MODE_DATA[self.mode]
     except KeyError:
       raise errors.ProgrammerError("Unknown mode '%s' passed to the"
                                    " IAllocator" % self.mode)
 
+    keyset = [n for (n, _) in keydata]
+
     for key in kwargs:
       if key not in keyset:
         raise errors.ProgrammerError("Invalid input parameter '%s' to"
@@ -12035,7 +12037,7 @@ class IAllocator(object):
       if key not in kwargs:
         raise errors.ProgrammerError("Missing input parameter '%s' to"
                                      " IAllocator" % key)
-    self._BuildInputData(compat.partial(fn, self))
+    self._BuildInputData(compat.partial(fn, self), keydata)
 
   def _ComputeClusterData(self):
     """Compute the generic allocator input data.
@@ -12310,7 +12312,7 @@ class IAllocator(object):
       "target_groups": self.target_groups,
       }
 
-  def _BuildInputData(self, fn):
+  def _BuildInputData(self, fn, keydata):
     """Build input data structures.
 
     """
@@ -12318,23 +12320,47 @@ class IAllocator(object):
 
     request = fn()
     request["type"] = self.mode
+    for keyname, keytype in keydata:
+      if keyname not in request:
+        raise errors.ProgrammerError("Request parameter %s is missing" %
+                                     keyname)
+      val = request[keyname]
+      if not keytype(val):
+        raise errors.ProgrammerError("Request parameter %s doesn't pass"
+                                     " validation, value %s, expected"
+                                     " type %s" % (keyname, val, keytype))
     self.in_data["request"] = request
 
     self.in_text = serializer.Dump(self.in_data)
 
+  _STRING_LIST = ht.TListOf(ht.TString)
   _MODE_DATA = {
     constants.IALLOCATOR_MODE_ALLOC:
       (_AddNewInstance,
-       ["name", "memory", "disks", "disk_template", "os", "tags", "nics",
-        "vcpus", "hypervisor"], ht.TList),
+       [
+        ("name", ht.TString),
+        ("memory", ht.TInt),
+        ("disks", ht.TListOf(ht.TDict)),
+        ("disk_template", ht.TString),
+        ("os", ht.TString),
+        ("tags", _STRING_LIST),
+        ("nics", ht.TListOf(ht.TDict)),
+        ("vcpus", ht.TInt),
+        ("hypervisor", ht.TString),
+        ], ht.TList),
     constants.IALLOCATOR_MODE_RELOC:
-      (_AddRelocateInstance, ["name", "relocate_from"], ht.TList),
+      (_AddRelocateInstance,
+       [("name", ht.TString), ("relocate_from", _STRING_LIST)],
+       ht.TList),
     constants.IALLOCATOR_MODE_MEVAC:
-      (_AddEvacuateNodes, ["evac_nodes"],
-       ht.TListOf(ht.TAnd(ht.TIsLength(2),
-                          ht.TListOf(ht.TString)))),
+      (_AddEvacuateNodes, [("evac_nodes", _STRING_LIST)],
+       ht.TListOf(ht.TAnd(ht.TIsLength(2), _STRING_LIST))),
     constants.IALLOCATOR_MODE_MRELOC:
-      (_AddMultiRelocate, ["instances", "reloc_mode", "target_groups"],
+      (_AddMultiRelocate, [
+        ("instances", _STRING_LIST),
+        ("reloc_mode", ht.TElemOf(constants.IALLOCATOR_MRELOC_MODES)),
+        ("target_groups", _STRING_LIST),
+        ],
        ht.TListOf(ht.TListOf(ht.TStrictDict(True, False, {
          # pylint: disable-msg=E1101
          # Class '...' has no 'OP_ID' member