Repository: conan-io/conan
Pull request #18646 (2025-07-15 10:15:29)

Add explicit error when trying to export a reference with `channel` but no `user`
Changelog: Fix: Add explicit error when trying to export a reference with `channel` but no `user`
Docs: https://github.com/conan-io/docs/pull/4167

This used to throw an assert exception, now it nicely throws a ConanException before any damage can be done

Close https://github.com/conan-io/conan/issues/18645


Patch:
diff --git a/conan/internal/loader.py b/conan/internal/loader.py
index 75b10db35..f3634ee9a 100644
--- a/conan/internal/loader.py
+++ b/conan/internal/loader.py
@@ -133,6 +133,9 @@ class ConanFileLoader:
                                      % (channel, conanfile.channel))
             conanfile.channel = channel
 
+        if conanfile.channel and not conanfile.user:
+            raise ConanException(f"{conanfile_path}: Can't specify channel '{conanfile.channel}' without user")
+
         if hasattr(conanfile, "set_name"):
             with conanfile_exception_formatter("conanfile.py", "set_name"):
                 conanfile.set_name()
@@ -167,8 +170,6 @@ class ConanFileLoader:
                                     remotes, update, check_update,
                                     tested_python_requires=tested_python_requires)
 
-        if conanfile.channel and not conanfile.user:
-            raise ConanException(f"{conanfile_path}: Can't specify channel without user")
         ref = RecipeReference(conanfile.name, conanfile.version, conanfile.user, conanfile.channel)
         if str(ref):
             conanfile.display_name = "%s (%s)" % (os.path.basename(conanfile_path), str(ref))


Test patch:
diff --git a/test/integration/command/export/export_test.py b/test/integration/command/export/export_test.py
index 8bd40f9e9..01b976c85 100644
--- a/test/integration/command/export/export_test.py
+++ b/test/integration/command/export/export_test.py
@@ -33,6 +33,22 @@ class TestExportSettings:
         client.save({"conanfile.py": GenConanfile("lib", "1.0")})
         client.run("export . --user=lasote")
         assert "lib/1.0@lasote: Exporting package recipe" in client.out
+        client.run("export . --channel=channel", assert_error=True)
+        assert "Can't specify channel 'channel' without user" in client.out
+
+        client.save({"conanfile.py": GenConanfile("lib", "1.0").with_class_attribute('channel = "channel"')})
+        client.run("export .", assert_error=True)
+        assert "Can't specify channel 'channel' without user" in client.out
+
+        client.run("export . --user=user")
+        assert "Exported: lib/1.0@user/channel" in client.out
+
+        client.save({"conanfile.py": GenConanfile("lib", "1.0").with_class_attribute('user = "user"')})
+        client.run("export .")
+        assert "lib/1.0@user: Exported" in client.out
+        client.run("export . --channel=channel")
+        assert "lib/1.0@user/channel: Exported" in client.out
+
 
     def test_export_read_only(self):
         client = TestClient(light=True)
diff --git a/test/integration/command/install/install_test.py b/test/integration/command/install/install_test.py
index 81e1c51d2..e0e252764 100644
--- a/test/integration/command/install/install_test.py
+++ b/test/integration/command/install/install_test.py
@@ -32,7 +32,7 @@ def test_install_reference_error(client):
     assert "ERROR: Can't use --name, --version, --user or --channel arguments with --requires" in client.out
     client.save({"conanfile.py": GenConanfile("pkg", "1.0")})
     client.run("install . --channel=testing", assert_error=True)
-    assert "Can't specify channel without user" in client.out
+    assert "Can't specify channel 'testing' without user" in client.out
 
 
 def test_install_args_error():