def _validate_inputs(actual_inputs, required_inputs, keypath=None):
    """
    Validate inputs.  Raise exception if something is missing.

    args:
        actual_inputs:  the object/dictionary passed to a subclass of 
            PublishablePayload
        required_inputs: the object/dictionary containing keys (and subkeys)
            for required fields.  (See get_common_payload_template.)
        keypath: used internally in recursive function calls.

    return:
        Nothing.  An exception will be raised if a problem is encountered.
    """
    actual_keys = set(actual_inputs.keys())
    required_keys = set(required_inputs.keys())
    if actual_keys.intersection(required_keys) != required_keys:
        prefix = '%s.' if keypath else ''
        output_keys = {'%s%s' % (prefix, key) for key in required_keys}
        raise Exception("Missing input fields.  Expected %s." % ', '.join(output_keys))
    for key in required_keys:
        # TODO: review the following usage of isinstance.
        # Will this always be appropriate, given duck typing?
        if isinstance(required_inputs[key], dict):
            new_keypath = key if not keypath else '%s.%s' % (keypath, key)
            _validate_inputs(
                actual_inputs=actual_inputs[key],
                required_inputs=required_inputs[key],
                keypath=new_keypath
            )