diff --git a/lib/spack/spack/fetch_strategy.py b/lib/spack/spack/fetch_strategy.py
index 481221181272b2d384276541535900d86263cf4b..8105402f99b87ecc1a3e0918e60fb97fac39767d 100644
--- a/lib/spack/spack/fetch_strategy.py
+++ b/lib/spack/spack/fetch_strategy.py
@@ -201,28 +201,16 @@ class BundleFetchStrategy(FetchStrategy):
     url_attr = ''
 
     def fetch(self):
-        tty.msg("No code to fetch.")
+        """Simply report success -- there is no code to fetch."""
         return True
 
-    def check(self):
-        tty.msg("No code to check.")
-
-    def expand(self):
-        tty.msg("No archive to expand.")
-
-    def reset(self):
-        tty.msg("No code to reset.")
-
-    def archive(self, destination):
-        tty.msg("No code to archive.")
-
     @property
     def cachable(self):
-        tty.msg("No code to cache.")
+        """Report False as there is no code to cache."""
         return False
 
     def source_id(self):
-        tty.msg("No code to be uniquely identified.")
+        """BundlePackages don't have a source id."""
         return ''
 
 
diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py
index b49c8c1a23115351b2b39bbbce4c385cfa52ae0b..8a65d7b73357584b57d107c62c2e6a75e6d9e1ef 100644
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -1046,7 +1046,9 @@ def do_fetch(self, mirror_only=False):
             raise ValueError("Can only fetch concrete packages.")
 
         if not self.has_code:
-            raise InvalidPackageOpError("Can only fetch a package with a URL.")
+            tty.msg(
+                "No fetch required for %s: package has no code." % self.name
+            )
 
         start_time = time.time()
         checksum = spack.config.get('config:checksum')
diff --git a/lib/spack/spack/test/install.py b/lib/spack/spack/test/install.py
index e0a83f20b2dc60346dc442db4b807bea8bb26c57..571e9fcd5841325dba2700ca3eadf87b5fc840da 100644
--- a/lib/spack/spack/test/install.py
+++ b/lib/spack/spack/test/install.py
@@ -9,8 +9,7 @@
 
 from llnl.util.filesystem import mkdirp, touch, working_dir
 
-from spack.package import \
-    InstallError, InvalidPackageOpError, PackageBase, PackageStillNeededError
+from spack.package import InstallError, PackageBase, PackageStillNeededError
 import spack.patch
 import spack.repo
 import spack.store
@@ -327,7 +326,9 @@ def test_uninstall_by_spec_errors(mutable_database):
         PackageBase.uninstall_by_spec(rec.spec)
 
 
-def test_nosource_pkg_install(install_mockery, mock_fetch, mock_packages):
+@pytest.mark.disable_clean_stage_check
+def test_nosource_pkg_install(
+        install_mockery, mock_fetch, mock_packages, capfd):
     """Test install phases with the nosource package."""
     spec = Spec('nosource').concretized()
     pkg = spec.package
@@ -336,9 +337,8 @@ def test_nosource_pkg_install(install_mockery, mock_fetch, mock_packages):
     pkg.do_install()
 
     # Also make sure an error is raised if `do_fetch` is called.
-    with pytest.raises(InvalidPackageOpError,
-                       match="fetch a package with a URL"):
-        pkg.do_fetch()
+    pkg.do_fetch()
+    assert "No fetch required for nosource" in capfd.readouterr()[0]
 
 
 def test_nosource_pkg_install_post_install(