diff --git a/libtaskotron/directives/koji_directive.py b/libtaskotron/directives/koji_directive.py
--- a/libtaskotron/directives/koji_directive.py
+++ b/libtaskotron/directives/koji_directive.py
@@ -13,35 +13,39 @@
   a specific build, or you can download all RPMs from all builds belonging
   to a specific Koji tag.
 parameters:
+  action:
+    required: true
+    description: choose whether to download a single build or all builds
+      belonging to a Koji tag
+    type: str
+    choices: [tag, build]
   arch:
     required: true
     description: |
       a list of architectures for which to download RPMs for the requested
-      build/tag. In addition to architectures supported by Taskotron by default,
-      ``src`` is supported as well.
+      build/tag. If you want to download RPMs for all arches, use ``['all']``.
 
       Note: ``noarch`` RPMs are always automatically downloaded even when not
-      requested, unless ``src`` is the only architecture requested.
+      requested, unless ``arch=[]`` and ``src=True``.
     type: list of str
-    choices: [standard Taskotron architectures, src]
-  command:
-    required: true
-    description: choose whether to download a single build or all builds
-      belonging to a Koji tag
-    type: str
-    choices: [tag, build]
+    choices: [supported architectures, ['all']]
   koji_build:
     required: true
     description: |
       N(E)VR of a Koji build to download. Only required when
-      ``command="download"``. Example: ``xchat-2.8.8-21.fc20``
+      ``action="download"``. Example: ``xchat-2.8.8-21.fc20``
     type: str
   koji_tag:
     required: true
     description: |
       name of a Koji tag to download all builds from. Only required when
-      ``command="download_tag"``. Example: ``f20-updates-pending``
+      ``action="download_tag"``. Example: ``f20-updates-pending``
     type: str
+  src:
+    required: false
+    description: download also ``src`` RPM files
+    type: bool
+    default: False
   target_dir:
     required: false
     description: directory into which to download builds
@@ -54,19 +58,24 @@
     RPMs
 raises: |
   * :class:`.TaskotronRemoteError`: if downloading failed
+  * :class:`.TaskotronValueError`: if ``arch=[]`` and ``src=False``, therefore
+    there is nothing to download
 version_added: 0.4
 """
 
 EXAMPLES = """
-Rpmlint needs to download a specific build from Koji::
+Rpmlint needs to download a specific build from Koji, all architectures
+including src.rpm::
 
   - name: download rpms from koji
     koji:
       action: download
       koji_build: ${koji_build}
-      arch: ${arch}
+      arch: ['all']
+      src: True
 
-Depcheck needs to download all builds in a specific Koji tag::
+Depcheck needs to download all builds in a specific Koji tag for the current
+architecture::
 
   - name: download koji tag
     koji:
@@ -77,10 +86,9 @@
 """
 
 from libtaskotron.koji_utils import KojiClient
-from libtaskotron.logger import log
 from libtaskotron.directives import BaseDirective
-from libtaskotron.exceptions import TaskotronDirectiveError
 from libtaskotron import rpm_utils
+import libtaskotron.exceptions as exc
 
 directive_class = 'KojiDirective'
 
@@ -94,60 +102,55 @@
             self.koji = koji_session
 
     def process(self, input_data, env_data):
+        # process params
         valid_actions = ['download', 'download_tag']
-
-        output_data = {}
-
         action = input_data['action']
-
         if not action in valid_actions:
-            raise TaskotronDirectiveError('%s is not a valid command for koji '
-                                          'helper' % action)
-
-        if 'arch' not in input_data:
-            detected_args = ', '.join(input_data.keys())
-            raise TaskotronDirectiveError(
-                "The koji directive requires 'arch' as an argument. Detected"
-                "arguments: %s" % detected_args)
+            raise exc.TaskotronDirectiveError('%s is not a valid action for koji '
+                                              'directive' % action)
 
         if not 'target_dir' in input_data:
             self.target_dir = env_data['workdir']
         else:
             self.target_dir = input_data['target_dir']
 
-        self.arches = input_data['arch']
+        if 'arch' not in input_data:
+            detected_args = ', '.join(input_data.keys())
+            raise exc.TaskotronDirectiveError(
+                "The koji directive requires 'arch' as an argument. Detected "
+                "arguments: %s" % detected_args)
 
-        if 'noarch' not in self.arches and not self.arches == ['src']:
+        self.arches = input_data['arch']
+        if self.arches and ('noarch' not in self.arches):
             self.arches.append('noarch')
 
+        self.src = input_data.get('src', False)
+
+        # download files
+        output_data = {}
+
         if action == 'download':
             if 'koji_build' not in input_data:
                 detected_args = ', '.join(input_data.keys())
-                raise TaskotronDirectiveError(
-                    "The koji directive requires 'koji_build' for the 'download'"
+                raise exc.TaskotronDirectiveError(
+                    "The koji directive requires 'koji_build' for the 'download' "
                     "action. Detected arguments: %s" % detected_args)
 
             nvr = rpm_utils.rpmformat(input_data['koji_build'], 'nvr')
 
-            log.info("Getting RPMs for koji build %s (%s) and downloading to %s",
-                     nvr, str(self.arches), self.target_dir)
             output_data['downloaded_rpms'] = self.koji.get_nvr_rpms(nvr,
-                                                                self.target_dir,
-                                                                arches=self.arches,
-                                                                src=('src' in self.arches))
+                self.target_dir, arches=self.arches, src=self.src)
+
         elif action == 'download_tag':
             if 'koji_tag' not in input_data:
                 detected_args = ', '.join(input_data.keys())
-                raise TaskotronDirectiveError(
-                    "The koji directive requires 'koji_tag' for the 'download_tag'"
+                raise exc.TaskotronDirectiveError(
+                    "The koji directive requires 'koji_tag' for the 'download_tag' "
                     "action. Detected arguments: %s" % detected_args)
 
             koji_tag = input_data['koji_tag']
 
-            log.info("Getting koji builds for koji tag '%s', arches '%s' and "
-                     "downloading to %s", koji_tag, str(self.arches), self.target_dir)
             output_data['downloaded_rpms'] = self.koji.get_tagged_rpms(koji_tag,
-                                                                self.target_dir,
-                                                                self.arches)
+                self.target_dir, arches=self.arches, src=self.src)
 
         return output_data
diff --git a/libtaskotron/koji_utils.py b/libtaskotron/koji_utils.py
--- a/libtaskotron/koji_utils.py
+++ b/libtaskotron/koji_utils.py
@@ -35,6 +35,7 @@
         self.session = (koji_session or
             koji.ClientSession(config.get_config().koji_url))
 
+
     def rpms_to_build(self, rpms):
         '''Get list of koji build objects for the rpms. Order of koji objects
         in this list is the same as order of the respective rpm objects.
@@ -105,93 +106,103 @@
 
         return result
 
-    def nvr_to_urls(self, nvr, arches=None, debuginfo=False, src=True):
+
+    def nvr_to_urls(self, nvr, arches=['all'], debuginfo=False, src=True):
         '''Get list of URLs for RPMs corresponding to a build.
 
         :param str nvr: build NVR
         :param arches: restrict the arches of builds to provide URLs for. By
-            default, all architectures are considered. If provided, only those
-            arches specified in the list are considered.
+            default, all architectures are considered. If you want to consider
+            just some selected arches, provide their names in a list.
 
             .. note:: If basearch ``i386`` is in the list, ``i686`` arch is
               automatically added (since that's the arch Koji API uses).
         :type arches: list of str
         :param bool debuginfo: whether to provide URLs for debuginfo RPM files
-            as well
-        :param bool src: whether to provide URLs for source RPMs as well
+            or ignore them
+        :param bool src: whether to include a URL for the source RPM
         :rtype: list of str
+        :raise TaskotronRemoteError: when the requested build doesn't exist
+        :raise TaskotronValueError: if ``arches=[]`` and ``src=False``,
+            therefore there is nothing to query for
         '''
         log.info('Querying Koji for a list of RPMS for: %s', nvr)
 
         # add i686 arch if i386 is present in arches
-        if arches and 'i386' in arches and 'i686' not in arches:
+        if 'i386' in arches and 'i686' not in arches:
             arches.append('i686')
 
+        # if src is enabled, we need to add it so that it is included in the
+        # Koji query
+        if src and ('src' not in arches):
+            arches.append('src')
+
+        # if "nothing" is requested, it's probably an error
+        if not arches:
+            raise exc.TaskotronValueError('Nothing to query for, `arches` was '
+                'set to an empty list and `src` was disabled. At least one of '
+                'them need to be non-empty.')
+
+        # find the koji build
         info = self.session.getBuild(nvr)
         if info is None:
             raise exc.TaskotronRemoteError(
-                "No build information found for %s" % nvr)
-
-        baseurl = '/'.join((config.get_config().pkg_url, info['package_name'],
-                            info['version'], info['release']))
+                "No such build found in Koji: %s" % nvr)
 
-        rpms = self.session.listRPMs(buildID=info['id'], arches=arches)
+        # list its RPM files
+        req_arches = None if 'all' in arches else arches
+        rpms = self.session.listRPMs(buildID=info['id'], arches=req_arches)
         if not debuginfo:
             rpms = [r for r in rpms if not r['name'].endswith('-debuginfo')]
         if not src:
             rpms = [r for r in rpms if not r['arch'] == 'src']
 
+        # create URLs
+        baseurl = '/'.join((config.get_config().pkg_url, info['package_name'],
+                            info['version'], info['release']))
         urls = ['%s/%s' % (baseurl, koji.pathinfo.rpm(r)) for r in rpms]
-        if len(urls) == 0:
-            raise exc.TaskotronRemoteError('No RPMs found for %s' % nvr)
 
         return sorted(urls)
 
 
-    def get_nvr_rpms(self, nvr, rpm_dir, arches=None, debuginfo=False,
+    def get_nvr_rpms(self, nvr, dest, arches=['all'], debuginfo=False,
                      src=False):
         '''Retrieve the RPMs associated with a build NVR into the specified
         directory.
 
-        :param str nvr build: NVR
-        :param str rpm_dir: location where to store the RPMs
+        :param str nvr: build NVR
+        :param str dest: location where to store the RPMs
         :param arches: see :meth:`nvr_to_urls`
         :param debuginfo: see :meth:`nvr_to_urls`
         :param src: see :meth:`nvr_to_urls`
         :return: list of local filenames of the grabbed RPMs
         :rtype: list of str
-        :raise TaskotronRemoteError: if issues with target directory
+        :raise TaskotronRemoteError: if the files can't be downloaded or saved
+        :raise TaskotronValueError: if ``arches=[]`` and ``src=False``,
+            therefore there is nothing to download
         '''
 
-        try:
-            rpm_urls = self.nvr_to_urls(nvr,
-                                        arches=arches,
-                                        debuginfo=debuginfo,
-                                        src=src)
-        except exc.TaskotronRemoteError, e:
-            log.warn('Error while retrieving urls for %s (%s)' % (nvr, arches))
-            log.warn(e)
-            return
+        rpm_urls = self.nvr_to_urls(nvr, arches, debuginfo, src)
 
         rpm_files = []
-        log.info('Fetching %s RPMs for: %s', len(rpm_urls), nvr)
+        log.info('Fetching %s RPMs for: %s (into %s)', len(rpm_urls), nvr, dest)
         for url in rpm_urls:
-            rpm_file = file_utils.download(url, rpm_dir)
+            rpm_file = file_utils.download(url, dest)
             rpm_files.append(rpm_file)
 
         return rpm_files
 
 
-    def get_tagged_rpms(self, tag, dest, arches):
+    def get_tagged_rpms(self, tag, dest, arches=['all'], debuginfo=False,
+                        src=False):
         '''Downloads all RPMs of all NVRs tagged by a specific Koji tag.
 
+        Note: This works basically the same as :meth:`get_nvr_rpms`, it just
+        downloads a lot of builds instead of a single one. For description of
+        all shared parameters and return values, please see that method.
+
         :param str tag: Koji tag to be queried for available builds, e.g.
                         ``f20-updates-pending``
-        :param str dest: destination directory
-        :param arches: see :meth:`nvr_to_urls`
-        :return: list of local filenames of the grabbed RPMs
-        :rtype: list of str
-        :raise TaskotronRemoteError: if issues with target directory
         '''
         log.debug('Querying Koji for tag: %s' % tag)
         tag_data = self.session.listTagged(tag)
@@ -202,7 +213,7 @@
         log.debug('Builds to be downloaded:\n  %s', '\n  '.join(nvrs))
 
         for nvr in nvrs:
-            rpms.append(self.get_nvr_rpms(nvr, dest, arches))
+            rpms.append(self.get_nvr_rpms(nvr, dest, arches, debuginfo, src))
 
         return rpms
 
diff --git a/testing/functest_koji_utils.py b/testing/functest_koji_utils.py
new file mode 100644
--- /dev/null
+++ b/testing/functest_koji_utils.py
@@ -0,0 +1,37 @@
+# -*- coding: utf-8 -*-
+# Copyright 2014, Red Hat, Inc.
+# License: GPL-2.0+ <http://spdx.org/licenses/GPL-2.0+>
+# See the LICENSE file for more details on Licensing
+
+'''Functional tests for libtaskotron/koji_utils.py'''
+
+from libtaskotron import koji_utils
+
+from dingus import Dingus
+
+
+class TestKojiClient():
+
+    def setup_method(self, method):
+        self.ref_nvr = 'foo-1.2-3.fc99'
+        self.ref_arch = 'noarch'
+        self.ref_name = 'foo'
+        self.ref_version = '1.2'
+        self.ref_release = '3.fc99'
+        self.ref_buildid = 123456
+
+        self.ref_build = {'package_name': self.ref_name,
+                          'version': self.ref_version,
+                          'release': self.ref_release,
+                          'id': self.ref_buildid}
+
+    def test_handle_norpms_in_build(self, tmpdir):
+        """ This tests to make sure that missing rpms in a build are handled
+        gracefully during download so that execution isn't stopped when a build
+        is missing an rpm """
+
+        rpmdir = tmpdir.mkdir("rpmdownload")
+        stub_koji = Dingus(getBuild__returns = self.ref_build)
+        test_koji = koji_utils.KojiClient(stub_koji)
+
+        test_koji.get_nvr_rpms(self.ref_nvr, str(rpmdir), arches=[self.ref_arch])
diff --git a/testing/test_koji_directive.py b/testing/test_koji_directive.py
--- a/testing/test_koji_directive.py
+++ b/testing/test_koji_directive.py
@@ -130,14 +130,14 @@
         test_helper.process(ref_input, ref_envdata)
 
         getrpm_calls = stub_koji.calls()
-        requested_arches = getrpm_calls[0][1][2]
+        requested_arches = getrpm_calls[0][2]['arches']
 
         assert len(getrpm_calls) == 1
         assert 'x86_64' in requested_arches
         assert 'noarch' in requested_arches
 
     def test__download_command_src(self):
-        ref_input = {'action': 'download', 'arch': ['src'],
+        ref_input = {'action': 'download', 'arch': [], 'src': True,
                      'koji_build': self.ref_nvr}
         ref_envdata = {'workdir': '/var/tmp/foo'}
 
@@ -150,5 +150,5 @@
         requested_src = getrpm_calls[0][2]['src']
 
         assert len(getrpm_calls) == 1
-        assert ['src'] == requested_arches
+        assert [] == requested_arches
         assert requested_src
diff --git a/testing/test_koji_utils.py b/testing/test_koji_utils.py
--- a/testing/test_koji_utils.py
+++ b/testing/test_koji_utils.py
@@ -140,26 +140,46 @@
         assert 'i686' in requested_arches
         assert 'i386' in requested_arches
 
-    def should_throw_exception_norpms(self):
+    def should_not_throw_exception_norpms(self):
+        '''It's possible to have no RPMs (for the given arch) in a build'''
         stub_koji = Dingus(getBuild__returns = self.ref_build)
+        test_koji = koji_utils.KojiClient(stub_koji)
+
+        test_koji.nvr_to_urls(self.ref_nvr, arches = [self.ref_arch])
 
+    def test_nvr_to_urls_src_filtering(self):
+        stub_koji = Dingus(getBuild__returns=self.ref_build,
+                           listRPMs__returns=self.ref_rpms)
         test_koji = koji_utils.KojiClient(stub_koji)
 
-        with pytest.raises(exc.TaskotronRemoteError):
-            test_koji.nvr_to_urls(self.ref_nvr, arches = [self.ref_arch])
+        # arch and src enabled
+        urls = test_koji.nvr_to_urls(self.ref_nvr, arches=[self.ref_arch])
+        assert len(urls) == 2
+        assert 'src' in urls[0] or 'src' in urls[1]
 
-    def test_handle_norpms_in_build(self, tmpdir):
-        """ This tests to make sure that missing rpms in a build are handled
-        gracefully during download so that execution isn't stopped when a build
-        is missing an rpm """
+        # arch enabled, src disabled
+        urls = test_koji.nvr_to_urls(self.ref_nvr, arches=[self.ref_arch],
+                                     src=False)
+        assert len(urls) == 1
+        assert 'src' not in urls[0]
 
-        rpmdir = tmpdir.mkdir("rpmdownload")
+    def test_nvr_to_urls_only_src(self):
+        stub_koji = Dingus(getBuild__returns=self.ref_build)
+        test_koji = koji_utils.KojiClient(stub_koji)
 
-        stub_koji = Dingus(getBuild__returns = self.ref_build)
+        # arch disabled, src enabled
+        test_koji.nvr_to_urls(self.ref_nvr, arches=[], src=True)
+        listrpm_calls = stub_koji.calls('listRPMs')
+        requested_arches = listrpm_calls[0][2]['arches']
+        assert len(requested_arches) == 1
+        assert requested_arches[0] == 'src'
 
+    def should_raise_no_arch_no_src(self):
+        stub_koji = Dingus()
         test_koji = koji_utils.KojiClient(stub_koji)
 
-        test_koji.get_nvr_rpms(self.ref_nvr, str(rpmdir), arches = [self.ref_arch])
+        with pytest.raises(exc.TaskotronValueError):
+            test_koji.nvr_to_urls(self.ref_nvr, arches=[], src=False)
 
 
 class TestGetENVR(object):

