Repository: tefra/xsdata
Pull request #970 (2024-03-09 16:55:48)

feat: Improve codegen errors
## 📒 Description

> Write a brief description of your PR.

Resolves #xxxx

## 🔗 What I've Done

> Write a description of the steps taken to resolve the issue

## 💬 Comments

> A place to write any comments to the reviewer.

## 🛫 Checklist

- [ ] Updated docs
- [ ] Added unit-tests
- [ ] [Sample tests](https://github.com/tefra/xsdata-samples) pass
- [ ] [W3C tests](https://github.com/tefra/xsdata-w3c-tests) pass


sonarcloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=tefra_xsdata&pullRequest=970) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=970&resolved=false&inNewCodePeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=970&metric=new_accepted_issues&view=list)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=970&resolved=false&inNewCodePeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/no-data-16px.png '') No data about Coverage  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=970&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=tefra_xsdata&pullRequest=970)


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/tefra/xsdata/pull/970?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou) Report
Attention: Patch coverage is `88.46154%` with `6 lines` in your changes are missing coverage. Please review.
> Project coverage is 99.89%. Comparing base [(`b8a2abc`)](https://app.codecov.io/gh/tefra/xsdata/commit/b8a2abcbc617ea67c5d49a756d645cf12964a16c?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou) to head [(`ef110be`)](https://app.codecov.io/gh/tefra/xsdata/pull/970?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou).

| [Files](https://app.codecov.io/gh/tefra/xsdata/pull/970?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou) | Patch % | Lines |
|---|---|---|
| [xsdata/codegen/exceptions.py](https://app.codecov.io/gh/tefra/xsdata/pull/970?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou#diff-eHNkYXRhL2NvZGVnZW4vZXhjZXB0aW9ucy5weQ==) | 66.66% | [4 Missing :warning: ](https://app.codecov.io/gh/tefra/xsdata/pull/970?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou) |
| [xsdata/codegen/transformer.py](https://app.codecov.io/gh/tefra/xsdata/pull/970?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou#diff-eHNkYXRhL2NvZGVnZW4vdHJhbnNmb3JtZXIucHk=) | 66.66% | [2 Missing :warning: ](https://app.codecov.io/gh/tefra/xsdata/pull/970?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou) |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main     #970      +/-   ##
==========================================
- Coverage   99.97%   99.89%   -0.08%     
==========================================
  Files         111      112       +1     
  Lines        8965     8971       +6     
  Branches     2134     2135       +1     
==========================================
- Hits         8963     8962       -1     
- Misses          1        7       +6     
- Partials        1        2       +1     
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/tefra/xsdata/pull/970?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou).

sonarcloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=tefra_xsdata&pullRequest=970) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=970&resolved=false&inNewCodePeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=970&metric=new_accepted_issues&view=list)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=970&resolved=false&inNewCodePeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/no-data-16px.png '') No data about Coverage  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=970&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=tefra_xsdata&pullRequest=970)


sonarcloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=tefra_xsdata&pullRequest=970) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=970&resolved=false&inNewCodePeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=970&metric=new_accepted_issues&view=list)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=970&resolved=false&inNewCodePeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/no-data-16px.png '') No data about Coverage  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=970&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=tefra_xsdata&pullRequest=970)



Patch:
diff --git a/xsdata/cli.py b/xsdata/cli.py
index 96945e62..3df251cd 100644
--- a/xsdata/cli.py
+++ b/xsdata/cli.py
@@ -42,6 +42,7 @@ def cli(ctx: click.Context, **kwargs: Any):
     """Xsdata command line interface."""
     logger.setLevel(logging.INFO)
     formatwarning_orig = warnings.formatwarning
+
     logger.info(
         "========= xsdata v%s / Python %s / Platform %s =========\n",
         __version__,
diff --git a/xsdata/codegen/exceptions.py b/xsdata/codegen/exceptions.py
new file mode 100644
index 00000000..b0bd081b
--- /dev/null
+++ b/xsdata/codegen/exceptions.py
@@ -0,0 +1,22 @@
+from typing import IO, Any, Optional
+
+from click import ClickException, echo
+
+
+class CodegenWarning(Warning):
+    """Recovered errors during code generation recovered errors."""
+
+
+class CodegenError(ClickException):
+    """Unexpected state during code generation related errors."""
+
+    def __init__(self, message: str, **kwargs: Any):
+        super().__init__(message)
+        self.meta = kwargs
+
+    def show(self, file: Optional[IO[Any]] = None):
+        """Echo codegen error message and details."""
+        echo("=========")
+        super().show(file)
+        for key, value in self.meta.items():
+            echo(f"{key}: {value}")
diff --git a/xsdata/codegen/handlers/designate_class_packages.py b/xsdata/codegen/handlers/designate_class_packages.py
index 160fa8ef..27a735f6 100644
--- a/xsdata/codegen/handlers/designate_class_packages.py
+++ b/xsdata/codegen/handlers/designate_class_packages.py
@@ -7,9 +7,9 @@ from urllib.parse import urlparse
 
 from toposort import toposort_flatten
 
+from xsdata.codegen.exceptions import CodegenError
 from xsdata.codegen.mixins import ContainerHandlerInterface
 from xsdata.codegen.models import Class, get_location, get_target_namespace
-from xsdata.exceptions import CodeGenerationError
 from xsdata.models.config import ObjectType, StructureStyle
 from xsdata.models.enums import COMMON_SCHEMA_DIR
 from xsdata.utils import collections
@@ -108,10 +108,11 @@ class DesignateClassPackages(ContainerHandlerInterface):
         """Group strongly connected classes together by namespaces."""
         for group in self.strongly_connected_classes():
             classes = self.sort_classes(group)
-            if len(set(map(get_target_namespace, classes))) > 1:
-                raise CodeGenerationError(
-                    "Found strongly connected classes from different "
-                    "namespaces, grouping them is impossible!"
+            namespaces = set(map(get_target_namespace, classes))
+            if len(namespaces) > 1:
+                raise CodegenError(
+                    "Found strongly connected types from different namespaces",
+                    namespaces=namespaces,
                 )
 
             parts = self.combine_ns_package(classes[0].target_namespace)
diff --git a/xsdata/codegen/handlers/flatten_attribute_groups.py b/xsdata/codegen/handlers/flatten_attribute_groups.py
index af7e9953..703aeaf2 100644
--- a/xsdata/codegen/handlers/flatten_attribute_groups.py
+++ b/xsdata/codegen/handlers/flatten_attribute_groups.py
@@ -1,7 +1,7 @@
+from xsdata.codegen.exceptions import CodegenError
 from xsdata.codegen.mixins import RelativeHandlerInterface
 from xsdata.codegen.models import Attr, Class
 from xsdata.codegen.utils import ClassUtils
-from xsdata.exceptions import AnalyzerValueError
 
 
 class FlattenAttributeGroups(RelativeHandlerInterface):
@@ -46,7 +46,7 @@ class FlattenAttributeGroups(RelativeHandlerInterface):
         source = self.container.find(qname, condition=lambda x: x.tag == attr.tag)
 
         if not source:
-            raise AnalyzerValueError(f"Group attribute not found: `{qname}`")
+            raise CodegenError("Unknown group reference", tag=attr.tag, qname=qname)
 
         if source is target:
             ClassUtils.remove_attribute(target, attr)
diff --git a/xsdata/codegen/handlers/validate_references.py b/xsdata/codegen/handlers/validate_references.py
index d5bebd46..5403ab6b 100644
--- a/xsdata/codegen/handlers/validate_references.py
+++ b/xsdata/codegen/handlers/validate_references.py
@@ -1,8 +1,8 @@
 from typing import Set
 
+from xsdata.codegen.exceptions import CodegenError
 from xsdata.codegen.mixins import ContainerHandlerInterface
 from xsdata.codegen.models import Class, get_qname
-from xsdata.exceptions import AnalyzerValueError
 from xsdata.utils import collections
 
 
@@ -31,7 +31,7 @@ class ValidateReferences(ContainerHandlerInterface):
                 duplicate_types.append(qname)
 
         if duplicate_types:
-            raise AnalyzerValueError("Duplicate types found", qnames=duplicate_types)
+            raise CodegenError("Duplicate types found", qnames=duplicate_types)
 
     def validate_unique_instances(self):
         """Validate all codegen instances are unique."""
@@ -39,7 +39,7 @@ class ValidateReferences(ContainerHandlerInterface):
         for item in self.container:
             item_references = {id(child) for child in item.children()}
             if item_references.intersection(references):
-                raise AnalyzerValueError("Cross reference detected", Class=item)
+                raise CodegenError("Cross reference detected", type=item.qname)
 
             references.update(item_references)
 
@@ -63,11 +63,11 @@ class ValidateReferences(ContainerHandlerInterface):
                     continue
 
                 if tp.reference not in references:
-                    raise AnalyzerValueError(
-                        "Unresolved reference detected", Class=item, AttrType=tp
+                    raise CodegenError(
+                        "Unresolved reference detected", cls=item.qname, type=tp.qname
                     )
 
                 if tp.qname != references[tp.reference]:
-                    raise AnalyzerValueError(
-                        "Misrepresented reference", Class=item, AttrType=tp
+                    raise CodegenError(
+                        "Misrepresented reference", cls=item.qname, type=tp.qname
                     )
diff --git a/xsdata/codegen/models.py b/xsdata/codegen/models.py
index b1c3a7f7..82fa0083 100644
--- a/xsdata/codegen/models.py
+++ b/xsdata/codegen/models.py
@@ -4,7 +4,7 @@ from dataclasses import asdict, dataclass, field, replace
 from enum import IntEnum
 from typing import Any, Dict, Iterator, List, Optional, Tuple, Type
 
-from xsdata.exceptions import CodeGenerationError
+from xsdata.codegen.exceptions import CodegenError
 from xsdata.formats.converter import converter
 from xsdata.formats.dataclass.models.elements import XmlType
 from xsdata.models.enums import DataType, Namespace, Tag
@@ -626,8 +626,8 @@ class Class(CodegenModel):
         if self.module:
             return self.module
 
-        raise CodeGenerationError(
-            f"Class `{self.name}` has not been assigned to a module yet!"
+        raise CodegenError(
+            "Type has not been assigned to a module yet!", type=self.qname
         )
 
     def clone(self) -> "Class":
diff --git a/xsdata/codegen/resolver.py b/xsdata/codegen/resolver.py
index 15ebf77a..58a7a82e 100644
--- a/xsdata/codegen/resolver.py
+++ b/xsdata/codegen/resolver.py
@@ -4,8 +4,8 @@ from typing import Dict, List
 
 from toposort import toposort_flatten
 
+from xsdata.codegen.exceptions import CodegenError
 from xsdata.codegen.models import Class, Import, get_slug
-from xsdata.exceptions import ResolverValueError
 from xsdata.utils import collections
 
 logger = logging.getLogger(__name__)
@@ -136,10 +136,10 @@ class DependenciesResolver:
             qname: The namespace qualified name of the class
 
         Raises:
-            ResolverValueError: if name doesn't exist.
+            CodeGenerationError: if name doesn't exist.
         """
         if qname not in self.registry:
-            raise ResolverValueError(f"Unknown dependency: {qname}")
+            raise CodegenError("Failed to resolve dependency", qname=qname)
         return self.registry[qname]
 
     def import_classes(self) -> List[str]:
@@ -156,7 +156,7 @@ class DependenciesResolver:
         """Index the list of classes by their qualified names.
 
         Raises:
-            ResolverValueError: If two classes have the same qname.
+            CodeGenerationError: If two classes have the same qname.
 
         Returns:
             A qname-class map.
@@ -164,7 +164,7 @@ class DependenciesResolver:
         result: Dict[str, Class] = {}
         for obj in classes:
             if obj.qname in result:
-                raise ResolverValueError(f"Duplicate class: `{obj.name}`")
+                raise CodegenError("Duplicate class during resolve", qname=obj.qname)
             result[obj.qname] = obj
 
         return result
diff --git a/xsdata/codegen/transformer.py b/xsdata/codegen/transformer.py
index 1549c33f..19c7a743 100644
--- a/xsdata/codegen/transformer.py
+++ b/xsdata/codegen/transformer.py
@@ -8,8 +8,11 @@ from collections import defaultdict
 from pathlib import Path
 from typing import Callable, Dict, List, NamedTuple, Optional, Tuple
 
+from toposort import CircularDependencyError
+
 from xsdata.codegen import opener
 from xsdata.codegen.container import ClassContainer
+from xsdata.codegen.exceptions import CodegenError
 from xsdata.codegen.mappers import (
     DefinitionsMapper,
     DictMapper,
@@ -23,7 +26,6 @@ from xsdata.codegen.parsers.definitions import DefinitionsParser
 from xsdata.codegen.parsers.schema import SchemaParser
 from xsdata.codegen.utils import ClassUtils
 from xsdata.codegen.writer import CodeWriter
-from xsdata.exceptions import CodeGenerationError
 from xsdata.formats.dataclass.models.generics import AnyElement
 from xsdata.formats.dataclass.parsers import TreeParser
 from xsdata.logger import logger
@@ -132,7 +134,13 @@ class ResourceTransformer:
         if cache_file and not cache_file.exists():
             cache_file.write_bytes(pickle.dumps(self.classes))
 
-        self.process_classes()
+        try:
+            self.process_classes()
+        except CircularDependencyError:
+            raise CodegenError(
+                "Circular Dependencies Found",
+                help="Try a different structure style and enabling unnest classes.",
+            )
 
     def process_sources(self, uris: List[str]):
         """Process a list of resolved URI strings.
@@ -274,8 +282,6 @@ class ResourceTransformer:
                 writer.print(classes)
             else:
                 writer.write(classes)
-        else:
-            raise CodeGenerationError("Nothing to generate.")
 
     def convert_schema(self, schema: Schema):
         """Convert a schema instance to codegen classes.
diff --git a/xsdata/codegen/utils.py b/xsdata/codegen/utils.py
index e963d4c5..2d9e219b 100644
--- a/xsdata/codegen/utils.py
+++ b/xsdata/codegen/utils.py
@@ -1,6 +1,7 @@
 import sys
 from typing import Iterator, List, Optional, Set
 
+from xsdata.codegen.exceptions import CodegenError
 from xsdata.codegen.models import (
     Attr,
     AttrType,
@@ -11,7 +12,6 @@ from xsdata.codegen.models import (
     get_qname,
     get_slug,
 )
-from xsdata.exceptions import CodeGenerationError
 from xsdata.models.enums import DataType
 from xsdata.utils import collections, namespaces, text
 
@@ -36,7 +36,7 @@ class ClassUtils:
             if not attr.xml_type:
                 return attr
 
-        raise CodeGenerationError(f"Class has no value attr {source.qname}")
+        raise CodegenError("Class has no value attr", type=source.qname)
 
     @classmethod
     def remove_attribute(cls, target: Class, attr: Attr):
@@ -225,7 +225,7 @@ class ClassUtils:
             if inner.qname == qname:
                 return inner
 
-        raise CodeGenerationError(f"Missing inner class {source.qname}.{qname}")
+        raise CodegenError("Missing inner class", parent=source, qname=qname)
 
     @classmethod
     def find_attr(cls, source: Class, name: str) -> Optional[Attr]:
diff --git a/xsdata/codegen/writer.py b/xsdata/codegen/writer.py
index cdae487a..df51e77f 100644
--- a/xsdata/codegen/writer.py
+++ b/xsdata/codegen/writer.py
@@ -1,7 +1,7 @@
 from typing import ClassVar, Dict, List, Type
 
+from xsdata.codegen.exceptions import CodegenError
 from xsdata.codegen.models import Class
-from xsdata.exceptions import CodeGenerationError
 from xsdata.formats.dataclass.generator import DataclassGenerator
 from xsdata.formats.mixins import AbstractGenerator
 from xsdata.logger import logger
@@ -73,8 +73,8 @@ class CodeWriter:
             A new code writer instance.
         """
         if config.output.format.value not in cls.generators:
-            raise CodeGenerationError(
-                f"Unknown output format: '{config.output.format.value}'"
+            raise CodegenError(
+                "Unknown output format", format=config.output.format.value
             )
 
         generator_class = cls.generators[config.output.format.value]
diff --git a/xsdata/exceptions.py b/xsdata/exceptions.py
index 3a1be5aa..e2e69a4c 100644
--- a/xsdata/exceptions.py
+++ b/xsdata/exceptions.py
@@ -1,18 +1,3 @@
-from typing import Any
-
-
-class CodeGenerationError(TypeError):
-    """Unexpected state during code generation related errors."""
-
-
-class CodeGenerationWarning(Warning):
-    """Recovered errors during code generation recovered errors."""
-
-
-class GeneratorConfigError(CodeGenerationError):
-    """Unexpected state during generator config related errors."""
-
-
 class ConverterError(ValueError):
     """Converting values between document/python types related errors."""
 
@@ -41,25 +26,5 @@ class XmlContextError(ValueError):
     """Unhandled behaviour during data binding."""
 
 
-class SchemaValueError(ValueError):
-    """Schema definitions related errors."""
-
-
-class DefinitionsValueError(ValueError):
-    """Service definitions related errors."""
-
-
-class AnalyzerValueError(ValueError):
-    """Unhandled behaviour during class analyze process."""
-
-    def __init__(self, message: str, **kwargs: Any):
-        super().__init__(message)
-        self.meta = kwargs
-
-
-class ResolverValueError(ValueError):
-    """Dependencies related errors."""
-
-
 class ClientValueError(ValueError):
     """Client related errors."""
diff --git a/xsdata/formats/dataclass/generator.py b/xsdata/formats/dataclass/generator.py
index 43884944..d5fce1cb 100644
--- a/xsdata/formats/dataclass/generator.py
+++ b/xsdata/formats/dataclass/generator.py
@@ -5,9 +5,9 @@ from typing import Iterator, List, Optional
 
 from jinja2 import Environment, FileSystemLoader
 
+from xsdata.codegen.exceptions import CodegenError
 from xsdata.codegen.models import Class, Import
 from xsdata.codegen.resolver import DependenciesResolver
-from xsdata.exceptions import CodeGenerationError
 from xsdata.formats.dataclass.filters import Filters
 from xsdata.formats.mixins import AbstractGenerator, GeneratorResult
 from xsdata.models.config import GeneratorConfig
@@ -242,4 +242,4 @@ class DataclassGenerator(AbstractGenerator):
             return src_code_encoded.decode()
         except subprocess.CalledProcessError as e:
             error = indent(e.stderr.decode(), "  ")
-            raise CodeGenerationError(f"Ruff failed:\n{error}")
+            raise CodegenError("Ruff failed", details=error)
diff --git a/xsdata/formats/mixins.py b/xsdata/formats/mixins.py
index 72cea541..dc978ca2 100644
--- a/xsdata/formats/mixins.py
+++ b/xsdata/formats/mixins.py
@@ -4,8 +4,8 @@ from pathlib import Path
 from typing import Dict, Iterator, List, NamedTuple
 
 from xsdata import __version__
+from xsdata.codegen.exceptions import CodegenError
 from xsdata.codegen.models import Class
-from xsdata.exceptions import CodeGenerationError
 from xsdata.models.config import GeneratorConfig
 from xsdata.utils.collections import group_by
 from xsdata.utils.package import module_path, package_path
@@ -86,7 +86,7 @@ class AbstractGenerator(abc.ABC):
         packages = {}
         for obj in classes:
             if obj.package is None or obj.module is None:
-                raise CodeGenerationError(
+                raise CodegenError(
                     f"Class `{obj.name}` has not been assigned to a package"
                 )
 
diff --git a/xsdata/models/config.py b/xsdata/models/config.py
index 85c875c1..52364a05 100644
--- a/xsdata/models/config.py
+++ b/xsdata/models/config.py
@@ -7,7 +7,7 @@ from pathlib import Path
 from typing import Any, Callable, Dict, List, Pattern, TextIO
 
 from xsdata import __version__
-from xsdata.exceptions import CodeGenerationWarning, GeneratorConfigError
+from xsdata.codegen.exceptions import CodegenError, CodegenWarning
 from xsdata.formats.dataclass.context import XmlContext
 from xsdata.formats.dataclass.parsers import XmlParser
 from xsdata.formats.dataclass.parsers.config import ParserConfig
@@ -164,21 +164,25 @@ class OutputFormat:
     def validate(self):
         """Validate and reset configuration conflicts."""
         if self.order and not self.eq:
-            raise GeneratorConfigError("eq must be true if order is true")
+            self.eq = True
+            warnings.warn(
+                "Enabling eq because order is true",
+                CodegenWarning,
+            )
 
         if self.value == "dataclasses" and sys.version_info < (3, 10):
             if self.slots:
                 self.slots = False
                 warnings.warn(
                     "slots requires python >= 3.10, reverting...",
-                    CodeGenerationWarning,
+                    CodegenWarning,
                 )
 
             if self.kw_only:
                 self.kw_only = False
                 warnings.warn(
                     "kw_only requires python >= 3.10, reverting...",
-                    CodeGenerationWarning,
+                    CodegenWarning,
                 )
 
 
@@ -253,21 +257,21 @@ class GeneratorOutput:
             self.subscriptable_types = False
             warnings.warn(
                 "Generics PEP 585 requires python >= 3.9, reverting...",
-                CodeGenerationWarning,
+                CodegenWarning,
             )
 
         if self.union_type and sys.version_info < (3, 10):
             self.union_type = False
             warnings.warn(
                 "UnionType PEP 604 requires python >= 3.10, reverting...",
-                CodeGenerationWarning,
+                CodegenWarning,
             )
 
         if self.union_type and not self.postponed_annotations:
             self.postponed_annotations = True
             warnings.warn(
                 "Enabling postponed annotations, because `union_type==True`",
-                CodeGenerationWarning,
+                CodegenWarning,
             )
 
     def update(self, **kwargs: Any):
@@ -428,14 +432,16 @@ class GeneratorExtension:
         try:
             self.module_path, self.func_name = self.import_string.rsplit(".", 1)
         except (ValueError, AttributeError):
-            raise GeneratorConfigError(
-                f"Invalid extension import '{self.import_string}'"
+            raise CodegenError(
+                "Invalid extension import string", value=self.import_string
             )
 
         try:
             self.pattern = re.compile(self.class_name)
         except re.error:
-            raise GeneratorConfigError(f"Failed to compile pattern '{self.class_name}'")
+            raise CodegenError(
+                "Failed to compile extension pattern", pattern=self.class_name
+            )
 
 
 @dataclass
diff --git a/xsdata/models/mixins.py b/xsdata/models/mixins.py
index d246350c..44c560c8 100644
--- a/xsdata/models/mixins.py
+++ b/xsdata/models/mixins.py
@@ -1,7 +1,7 @@
 from dataclasses import dataclass, field, fields
 from typing import Any, Callable, Dict, Iterator, List, Optional
 
-from xsdata.exceptions import SchemaValueError
+from xsdata.codegen.exceptions import CodegenError
 from xsdata.formats.dataclass.models.elements import XmlType
 from xsdata.models.enums import DataType, FormType, Namespace, NamespaceType
 from xsdata.utils import text
@@ -132,7 +132,9 @@ class ElementBase:
         if name:
             return text.suffix(name)
 
-        raise SchemaValueError(f"Schema class `{self.class_name}` unknown real name.")
+        raise CodegenError(
+            "Schema type can't be used as a class/field", type=self.class_name
+        )
 
     @property
     def attr_types(self) -> Iterator[str]:
diff --git a/xsdata/models/wsdl.py b/xsdata/models/wsdl.py
index 3051c3a8..04bd8e73 100644
--- a/xsdata/models/wsdl.py
+++ b/xsdata/models/wsdl.py
@@ -1,8 +1,8 @@
 from dataclasses import dataclass, field
 from typing import Dict, Iterator, List, Optional, TypeVar
 
+from xsdata.codegen.exceptions import CodegenError
 from xsdata.codegen.models import get_name
-from xsdata.exceptions import DefinitionsValueError
 from xsdata.formats.dataclass.models.generics import AnyElement
 from xsdata.models.enums import Namespace
 from xsdata.models.mixins import array_any_element, array_element, attribute, element
@@ -336,4 +336,4 @@ def find_or_die(items: List[T], name: str, type_name: str) -> T:
         if msg.name == name:
             return msg
 
-    raise DefinitionsValueError(f"Unknown {type_name} name: {name}")
+    raise CodegenError("Unknown WSDL Type", type=type_name, name=name)


Test patch:
diff --git a/tests/codegen/handlers/test_designate_class_packages.py b/tests/codegen/handlers/test_designate_class_packages.py
index 28bbb39b..2c0fff16 100644
--- a/tests/codegen/handlers/test_designate_class_packages.py
+++ b/tests/codegen/handlers/test_designate_class_packages.py
@@ -1,6 +1,6 @@
 from xsdata.codegen.container import ClassContainer
+from xsdata.codegen.exceptions import CodegenError
 from xsdata.codegen.handlers import DesignateClassPackages
-from xsdata.exceptions import CodeGenerationError
 from xsdata.models.config import (
     GeneratorConfig,
     GeneratorSubstitution,
@@ -177,15 +177,9 @@ class DesignateClassPackagesTests(FactoryTestCase):
         self.config.output.package = "models"
         self.container.extend(classes)
 
-        with self.assertRaises(CodeGenerationError) as cm:
+        with self.assertRaises(CodegenError):
             self.handler.run()
 
-        self.assertEqual(
-            "Found strongly connected classes from different namespaces, "
-            "grouping them is impossible!",
-            str(cm.exception),
-        )
-
     def test_combine_ns_package(self):
         namespace = "urn:foo-bar:add"
         result = self.handler.combine_ns_package(namespace)
diff --git a/tests/codegen/handlers/test_flatten_attribute_groups.py b/tests/codegen/handlers/test_flatten_attribute_groups.py
index 52307514..93c46b90 100644
--- a/tests/codegen/handlers/test_flatten_attribute_groups.py
+++ b/tests/codegen/handlers/test_flatten_attribute_groups.py
@@ -1,10 +1,10 @@
 from unittest import mock
 
 from xsdata.codegen.container import ClassContainer
+from xsdata.codegen.exceptions import CodegenError
 from xsdata.codegen.handlers import FlattenAttributeGroups
 from xsdata.codegen.models import Attr, Status
 from xsdata.codegen.utils import ClassUtils
-from xsdata.exceptions import AnalyzerValueError
 from xsdata.models.config import GeneratorConfig
 from xsdata.models.enums import Tag
 from xsdata.utils.testing import AttrFactory, ClassFactory, FactoryTestCase
@@ -91,7 +91,5 @@ class FlattenAttributeGroupsTests(FactoryTestCase):
         target = ClassFactory.create()
         target.attrs.append(group_attr)
 
-        with self.assertRaises(AnalyzerValueError) as cm:
+        with self.assertRaises(CodegenError):
             self.processor.process_attribute(target, group_attr)
-
-        self.assertEqual("Group attribute not found: `bar`", str(cm.exception))
diff --git a/tests/codegen/handlers/test_validate_references.py b/tests/codegen/handlers/test_validate_references.py
index a3595730..18b35d8c 100644
--- a/tests/codegen/handlers/test_validate_references.py
+++ b/tests/codegen/handlers/test_validate_references.py
@@ -1,6 +1,6 @@
 from xsdata.codegen.container import ClassContainer
+from xsdata.codegen.exceptions import CodegenError
 from xsdata.codegen.handlers import ValidateReferences
-from xsdata.exceptions import AnalyzerValueError
 from xsdata.models.config import (
     GeneratorConfig,
 )
@@ -25,11 +25,9 @@ class ValidateReferencesTests(FactoryTestCase):
         second = first.clone()
         self.container.extend([first, second])
 
-        with self.assertRaises(AnalyzerValueError) as cm:
+        with self.assertRaises(CodegenError):
             self.handler.run()
 
-        self.assertEqual("Duplicate types found", str(cm.exception))
-
     def test_validate_unique_instances(self):
         first = ClassFactory.create()
         first.extensions.append(ExtensionFactory.create())
@@ -37,22 +35,18 @@ class ValidateReferencesTests(FactoryTestCase):
         second.extensions = first.extensions
         self.container.extend([first, second])
 
-        with self.assertRaises(AnalyzerValueError) as cm:
+        with self.assertRaises(CodegenError):
             self.handler.run()
 
-        self.assertEqual("Cross reference detected", str(cm.exception))
-
     def test_validate_unresolved_references(self):
         first = ClassFactory.create()
         first.attrs.append(AttrFactory.create())
         first.attrs.append(AttrFactory.reference("foo"))
         self.container.add(first)
 
-        with self.assertRaises(AnalyzerValueError) as cm:
+        with self.assertRaises(CodegenError):
             self.handler.run()
 
-        self.assertEqual("Unresolved reference detected", str(cm.exception))
-
     def test_validate_misrepresented_references(self):
         first = ClassFactory.create()
         inner = ClassFactory.create()
@@ -64,7 +58,5 @@ class ValidateReferencesTests(FactoryTestCase):
         )
         self.container.add(first)
 
-        with self.assertRaises(AnalyzerValueError) as cm:
+        with self.assertRaises(CodegenError):
             self.handler.run()
-
-        self.assertEqual("Misrepresented reference", str(cm.exception))
diff --git a/tests/codegen/models/test_class.py b/tests/codegen/models/test_class.py
index 537181d3..c00b2ccb 100644
--- a/tests/codegen/models/test_class.py
+++ b/tests/codegen/models/test_class.py
@@ -1,6 +1,6 @@
 import sys
 
-from xsdata.exceptions import CodeGenerationError
+from xsdata.codegen.exceptions import CodegenError
 from xsdata.models.enums import DataType, Namespace, Tag
 from xsdata.utils.namespaces import build_qname
 from xsdata.utils.testing import (
@@ -157,14 +157,9 @@ class ClassTests(FactoryTestCase):
 
     def test_property_target_module(self):
         obj = ClassFactory.create(module=None, package=None)
-        with self.assertRaises(CodeGenerationError) as cm:
+        with self.assertRaises(CodegenError):
             obj.target_module
 
-        self.assertEqual(
-            f"Class `{obj.name}` has not been assigned to a module yet!",
-            str(cm.exception),
-        )
-
         obj.module = "bar"
         self.assertEqual("bar", obj.target_module)
 
diff --git a/tests/codegen/test_resolver.py b/tests/codegen/test_resolver.py
index 57d1ec3d..af8e44c1 100644
--- a/tests/codegen/test_resolver.py
+++ b/tests/codegen/test_resolver.py
@@ -1,8 +1,8 @@
 from unittest import mock
 
+from xsdata.codegen.exceptions import CodegenError
 from xsdata.codegen.models import Class
 from xsdata.codegen.resolver import DependenciesResolver
-from xsdata.exceptions import ResolverValueError
 from xsdata.models.enums import DataType
 from xsdata.utils.namespaces import build_qname
 from xsdata.utils.testing import (
@@ -194,7 +194,7 @@ class DependenciesResolverTest(FactoryTestCase):
         self.resolver.registry[class_a.qname] = "foo.bar"
 
         self.assertEqual("foo.bar", self.resolver.get_class_module(class_a.qname))
-        with self.assertRaises(ResolverValueError):
+        with self.assertRaises(CodegenError):
             self.resolver.get_class_module("nope")
 
     def test_import_classes(self):
@@ -209,11 +209,9 @@ class DependenciesResolverTest(FactoryTestCase):
 
     def test_create_class_map_for_duplicate_classes(self):
         classes = ClassFactory.list(2, qname="a")
-        with self.assertRaises(ResolverValueError) as cm:
+        with self.assertRaises(CodegenError):
             self.resolver.create_class_map(classes)
 
-        self.assertEqual("Duplicate class: `a`", str(cm.exception))
-
     @mock.patch.object(Class, "dependencies")
     def test_create_class_list(self, mock_dependencies):
         classes = ClassFactory.list(3)
diff --git a/tests/codegen/test_transformer.py b/tests/codegen/test_transformer.py
index e2d3a933..0cc139c9 100644
--- a/tests/codegen/test_transformer.py
+++ b/tests/codegen/test_transformer.py
@@ -3,7 +3,10 @@ import tempfile
 from pathlib import Path
 from unittest import mock
 
+from toposort import CircularDependencyError
+
 from xsdata.codegen.container import ClassContainer
+from xsdata.codegen.exceptions import CodegenError
 from xsdata.codegen.mappers import (
     DefinitionsMapper,
     DictMapper,
@@ -15,7 +18,6 @@ from xsdata.codegen.parsers import DefinitionsParser, DtdParser
 from xsdata.codegen.transformer import ResourceTransformer
 from xsdata.codegen.utils import ClassUtils
 from xsdata.codegen.writer import CodeWriter
-from xsdata.exceptions import CodeGenerationError
 from xsdata.formats.dataclass.models.generics import AnyElement
 from xsdata.formats.dataclass.parsers import TreeParser
 from xsdata.models.config import GeneratorConfig
@@ -104,6 +106,12 @@ class ResourceTransformerTests(FactoryTestCase):
             self.assertEqual(classes, pickle.loads(cache.read_bytes()))
             mock_process_classes.assert_called_once_with()
 
+    @mock.patch.object(ResourceTransformer, "process_classes")
+    def test_process_with_circular_dependencies_error(self, mock_process_classes):
+        mock_process_classes.side_effect = CircularDependencyError({})
+        with self.assertRaises(CodegenError):
+            self.transformer.process([])
+
     @mock.patch.object(ResourceTransformer, "convert_schema")
     @mock.patch.object(ResourceTransformer, "convert_definitions")
     @mock.patch.object(ResourceTransformer, "parse_definitions")
@@ -282,12 +290,6 @@ class ResourceTransformerTests(FactoryTestCase):
             ]
         )
 
-    def test_process_classes_with_zero_classes_after_analyze(self):
-        with self.assertRaises(CodeGenerationError) as cm:
-            self.transformer.process_classes()
-
-        self.assertEqual("Nothing to generate.", str(cm.exception))
-
     @mock.patch.object(ResourceTransformer, "convert_schema")
     @mock.patch.object(ResourceTransformer, "parse_schema")
     def test_process_schema(
@@ -456,8 +458,8 @@ class ResourceTransformerTests(FactoryTestCase):
 
     @mock.patch("xsdata.codegen.transformer.logger.warning")
     def test_load_resource_missing(self, mock_warning):
-        uri = "file://foo/bar.xsd"
-        result = self.transformer.load_resource(uri)
+        uri = Path.cwd().joinpath("foo/bar.xsd").as_uri()
+        result = self.transformer.process([uri])
         self.assertIsNone(result)
 
         mock_warning.assert_called_once_with("Resource not found %s", uri)
diff --git a/tests/codegen/test_utils.py b/tests/codegen/test_utils.py
index c656209d..2083fb19 100644
--- a/tests/codegen/test_utils.py
+++ b/tests/codegen/test_utils.py
@@ -2,9 +2,9 @@ import sys
 from typing import Generator
 from unittest import mock
 
+from xsdata.codegen.exceptions import CodegenError
 from xsdata.codegen.models import Restrictions, Status
 from xsdata.codegen.utils import ClassUtils
-from xsdata.exceptions import CodeGenerationError
 from xsdata.models.enums import DataType, Tag
 from xsdata.utils.testing import (
     AttrFactory,
@@ -18,13 +18,11 @@ from xsdata.utils.testing import (
 class ClassUtilsTests(FactoryTestCase):
     def test_find_value_attr(self):
         target = ClassFactory.create()
-        with self.assertRaises(CodeGenerationError) as cm:
+        with self.assertRaises(CodegenError):
             ClassUtils.find_value_attr(target)
 
-        self.assertEqual("Class has no value attr {xsdata}class_B", str(cm.exception))
-
         target.attrs.append(AttrFactory.element())
-        with self.assertRaises(CodeGenerationError) as cm:
+        with self.assertRaises(CodegenError):
             ClassUtils.find_value_attr(target)
 
         target.attrs.append(AttrFactory.extension())
@@ -213,7 +211,7 @@ class ClassUtilsTests(FactoryTestCase):
         target = ClassFactory.create()
         attr_type = AttrTypeFactory.create(forward=True, qname=target.qname)
 
-        with self.assertRaises(CodeGenerationError):
+        with self.assertRaises(CodegenError):
             ClassUtils.copy_inner_class(source, target, attr_type)
 
     def test_find_inner(self):
@@ -223,10 +221,9 @@ class ClassUtilsTests(FactoryTestCase):
         third = ClassFactory.enumeration(2, qname="{d}d")
         obj.inner.extend((first, second, third))
 
-        with self.assertRaises(CodeGenerationError) as cm:
+        with self.assertRaises(CodegenError):
             self.assertIsNone(ClassUtils.find_inner(obj, "nope"))
 
-        self.assertEqual("Missing inner class {a}parent.nope", str(cm.exception))
         self.assertEqual(first, ClassUtils.find_inner(obj, "{a}a"))
         self.assertEqual(second, ClassUtils.find_inner(obj, "{c}c"))
         self.assertEqual(third, ClassUtils.find_inner(obj, "{d}d"))
diff --git a/tests/codegen/test_writer.py b/tests/codegen/test_writer.py
index 38d3a315..950ea631 100644
--- a/tests/codegen/test_writer.py
+++ b/tests/codegen/test_writer.py
@@ -3,9 +3,9 @@ from tempfile import TemporaryDirectory
 from typing import Iterator, List
 from unittest import mock
 
+from xsdata.codegen.exceptions import CodegenError
 from xsdata.codegen.models import Class
 from xsdata.codegen.writer import CodeWriter
-from xsdata.exceptions import CodeGenerationError
 from xsdata.formats.dataclass.generator import DataclassGenerator
 from xsdata.formats.mixins import AbstractGenerator, GeneratorResult
 from xsdata.models.config import GeneratorConfig
@@ -72,11 +72,9 @@ class CodeWriterTests(FactoryTestCase):
         CodeWriter.unregister_generator("dataclasses")
         config = GeneratorConfig()
 
-        with self.assertRaises(CodeGenerationError) as cm:
+        with self.assertRaises(CodegenError):
             CodeWriter.from_config(config)
 
-        self.assertEqual("Unknown output format: 'dataclasses'", str(cm.exception))
-
         CodeWriter.register_generator("dataclasses", DataclassGenerator)
         writer = CodeWriter.from_config(config)
         self.assertIsInstance(writer.generator, DataclassGenerator)
diff --git a/tests/formats/dataclass/test_generator.py b/tests/formats/dataclass/test_generator.py
index bae7df8d..187894f4 100644
--- a/tests/formats/dataclass/test_generator.py
+++ b/tests/formats/dataclass/test_generator.py
@@ -2,8 +2,8 @@ import random
 from pathlib import Path
 from unittest import mock
 
+from xsdata.codegen.exceptions import CodegenError
 from xsdata.codegen.resolver import DependenciesResolver
-from xsdata.exceptions import CodeGenerationError
 from xsdata.formats.dataclass.generator import DataclassGenerator
 from xsdata.models.config import GeneratorConfig
 from xsdata.utils.testing import ClassFactory, FactoryTestCase
@@ -218,7 +218,5 @@ class DataclassGeneratorTests(FactoryTestCase):
         file_path = Path(__file__)
 
         self.generator.config.output.max_line_length = 55
-        with self.assertRaises(CodeGenerationError) as cm:
+        with self.assertRaises(CodegenError):
             self.generator.ruff_code(src_code, file_path)
-
-        self.assertIn("Ruff failed", str(cm.exception))
diff --git a/tests/formats/test_mixins.py b/tests/formats/test_mixins.py
index 212eb983..399c735f 100644
--- a/tests/formats/test_mixins.py
+++ b/tests/formats/test_mixins.py
@@ -3,8 +3,8 @@ from typing import Iterator, List
 from unittest import mock
 
 from xsdata import __version__
+from xsdata.codegen.exceptions import CodegenError
 from xsdata.codegen.models import Class
-from xsdata.exceptions import CodeGenerationError
 from xsdata.formats.mixins import AbstractGenerator, GeneratorResult
 from xsdata.models.config import GeneratorConfig
 from xsdata.utils.testing import ClassFactory, FactoryTestCase
@@ -45,13 +45,9 @@ class AbstractGeneratorTests(FactoryTestCase):
         self.assertEqual("mod", classes[1].module)
         self.assertEqual("mod", classes[2].module)
 
-        with self.assertRaises(CodeGenerationError) as cm:
+        with self.assertRaises(CodegenError):
             self.generator.normalize_packages(ClassFactory.list(1))
 
-        self.assertEqual(
-            "Class `class_B` has not been assigned to a package", str(cm.exception)
-        )
-
     @mock.patch("datetime.datetime", wraps=datetime.datetime)
     def test_render_header(self, mock_datetime):
         actual = self.generator.render_header()
diff --git a/tests/models/test_config.py b/tests/models/test_config.py
index 35423072..734d3bb8 100644
--- a/tests/models/test_config.py
+++ b/tests/models/test_config.py
@@ -5,7 +5,8 @@ from pathlib import Path
 from unittest import TestCase
 
 from xsdata import __version__
-from xsdata.exceptions import GeneratorConfigError, ParserError
+from xsdata.codegen.exceptions import CodegenError
+from xsdata.exceptions import ParserError
 from xsdata.models.config import (
     ExtensionType,
     GeneratorConfig,
@@ -127,11 +128,11 @@ class GeneratorConfigTests(TestCase):
         with self.assertRaises(ParserError):
             GeneratorConfig.read(file_path)
 
-    def test_format_with_invalid_state(self):
-        with self.assertRaises(GeneratorConfigError) as cm:
+    def test_format_with_invalid_eq_config(self):
+        with warnings.catch_warnings(record=True) as w:
             OutputFormat(eq=False, order=True)
 
-        self.assertEqual("eq must be true if order is true", str(cm.exception))
+        self.assertEqual("Enabling eq because order is true", str(w[-1].message))
 
     def test_subscriptable_types_requires_390(self):
         if sys.version_info < (3, 9):
@@ -200,15 +201,11 @@ class GeneratorConfigTests(TestCase):
     def test_extension_with_invalid_import_string(self):
         cases = [None, "", "bar"]
         for case in cases:
-            with self.assertRaises(GeneratorConfigError) as cm:
+            with self.assertRaises(CodegenError):
                 GeneratorExtension(type=ExtensionType.DECORATOR, import_string=case)
 
-            self.assertEqual(f"Invalid extension import '{case}'", str(cm.exception))
-
     def test_extension_with_invalid_class_name_pattern(self):
-        with self.assertRaises(GeneratorConfigError) as cm:
+        with self.assertRaises(CodegenError):
             GeneratorExtension(
                 type=ExtensionType.DECORATOR, import_string="a.b", class_name="*Foo"
             )
-
-        self.assertEqual("Failed to compile pattern '*Foo'", str(cm.exception))
diff --git a/tests/models/test_mixins.py b/tests/models/test_mixins.py
index 71bb9792..bc72edd8 100644
--- a/tests/models/test_mixins.py
+++ b/tests/models/test_mixins.py
@@ -1,7 +1,7 @@
 from typing import Generator, Iterator
 from unittest import TestCase
 
-from xsdata.exceptions import SchemaValueError
+from xsdata.codegen.exceptions import CodegenError
 from xsdata.models.enums import FormType, Namespace
 from xsdata.models.mixins import ElementBase
 from xsdata.models.xsd import Alternative, ComplexType, Element, SimpleType
@@ -145,7 +145,7 @@ class ElementBaseTests(TestCase):
     def test_property_real_name(self):
         element = ElementBase()
 
-        with self.assertRaises(SchemaValueError):
+        with self.assertRaises(CodegenError):
             element.real_name
 
         element.ref = "bar:foo"
diff --git a/tests/models/wsdl/test_definitions.py b/tests/models/wsdl/test_definitions.py
index 038a3e95..6f9fc523 100644
--- a/tests/models/wsdl/test_definitions.py
+++ b/tests/models/wsdl/test_definitions.py
@@ -2,7 +2,7 @@ import copy
 from typing import Generator
 from unittest import TestCase
 
-from xsdata.exceptions import DefinitionsValueError
+from xsdata.codegen.exceptions import CodegenError
 from xsdata.formats.dataclass.models.generics import AnyElement
 from xsdata.models.wsdl import Binding, Definitions, Message, PortType, Service, Types
 from xsdata.models.xsd import Schema
@@ -29,33 +29,27 @@ class DefinitionsTests(TestCase):
 
         self.assertEqual(res, obj.find_binding("foo"))
 
-        with self.assertRaises(DefinitionsValueError) as cm:
+        with self.assertRaises(CodegenError):
             obj.find_binding("nope")
 
-        self.assertEqual("Unknown Binding name: nope", str(cm.exception))
-
     def test_find_message(self):
         res = Message(name="foo")
         obj = Definitions(messages=[res])
 
         self.assertEqual(res, obj.find_message("foo"))
 
-        with self.assertRaises(DefinitionsValueError) as cm:
+        with self.assertRaises(CodegenError):
             obj.find_message("nope")
 
-        self.assertEqual("Unknown Message name: nope", str(cm.exception))
-
     def test_find_port_type(self):
         res = PortType(name="foo")
         obj = Definitions(port_types=[res])
 
         self.assertEqual(res, obj.find_port_type("foo"))
 
-        with self.assertRaises(DefinitionsValueError) as cm:
+        with self.assertRaises(CodegenError):
             obj.find_port_type("nope")
 
-        self.assertEqual("Unknown PortType name: nope", str(cm.exception))
-
     def test_merge(self):
         target = Definitions()
         source = Definitions()
diff --git a/tests/models/wsdl/test_port_type.py b/tests/models/wsdl/test_port_type.py
index f7236df3..090daba5 100644
--- a/tests/models/wsdl/test_port_type.py
+++ b/tests/models/wsdl/test_port_type.py
@@ -1,6 +1,6 @@
 from unittest import TestCase
 
-from xsdata.exceptions import DefinitionsValueError
+from xsdata.codegen.exceptions import CodegenError
 from xsdata.models.wsdl import PortType, PortTypeOperation
 
 
@@ -11,7 +11,5 @@ class PortTypeTests(TestCase):
 
         self.assertEqual(res, obj.find_operation("foo"))
 
-        with self.assertRaises(DefinitionsValueError) as cm:
+        with self.assertRaises(CodegenError):
             obj.find_operation("nope")
-
-        self.assertEqual("Unknown PortTypeOperation name: nope", str(cm.exception))
diff --git a/tests/models/xsd/test_attribute.py b/tests/models/xsd/test_attribute.py
index bdf3deb4..4625f4e6 100644
--- a/tests/models/xsd/test_attribute.py
+++ b/tests/models/xsd/test_attribute.py
@@ -1,6 +1,6 @@
 from unittest import TestCase
 
-from xsdata.exceptions import SchemaValueError
+from xsdata.codegen.exceptions import CodegenError
 from xsdata.models.enums import Namespace, UseType
 from xsdata.models.xsd import Attribute, Length, Restriction, SimpleType
 
@@ -33,7 +33,7 @@ class AttributeTests(TestCase):
         obj.name = "foo"
         self.assertEqual("foo", obj.real_name)
 
-        with self.assertRaises(SchemaValueError):
+        with self.assertRaises(CodegenError):
             Attribute().real_name
 
     def test_get_restrictions(self):
diff --git a/tests/models/xsd/test_element.py b/tests/models/xsd/test_element.py
index e9d8313f..81b37e5c 100644
--- a/tests/models/xsd/test_element.py
+++ b/tests/models/xsd/test_element.py
@@ -1,6 +1,6 @@
 from unittest import TestCase
 
-from xsdata.exceptions import SchemaValueError
+from xsdata.codegen.exceptions import CodegenError
 from xsdata.models.enums import Namespace
 from xsdata.models.xsd import (
     Alternative,
@@ -47,7 +47,7 @@ class ElementTests(TestCase):
         obj.name = "foo"
         self.assertEqual("foo", obj.real_name)
 
-        with self.assertRaises(SchemaValueError):
+        with self.assertRaises(CodegenError):
             obj = Element()
             obj.real_name
 
diff --git a/tests/test_cli.py b/tests/test_cli.py
index 604372c0..450203e8 100644
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -10,6 +10,7 @@ from click.testing import CliRunner
 from tests import fixtures_dir
 from xsdata import __version__
 from xsdata.cli import cli, resolve_source
+from xsdata.codegen.exceptions import CodegenError
 from xsdata.codegen.transformer import ResourceTransformer
 from xsdata.codegen.writer import CodeWriter
 from xsdata.formats.dataclass.generator import DataclassGenerator
@@ -48,6 +49,16 @@ class CliTests(TestCase):
         self.assertEqual(StructureStyle.FILENAMES, config.output.structure_style)
         self.assertEqual([source.as_uri()], mock_process.call_args[0][0])
 
+    @mock.patch.object(ResourceTransformer, "process")
+    def test_generate_with_error(self, mock_process):
+        mock_process.side_effect = CodegenError("Testing", foo="bar")
+
+        source = fixtures_dir.joinpath("defxmlschema/chapter03.xsd")
+        result = self.runner.invoke(cli, [str(source), "--package", "foo"])
+        expected = "=========\n" "Error: Testing\n" "foo: bar\n"
+
+        self.assertIn(expected, result.output)
+
     @mock.patch.object(ResourceTransformer, "process")
     @mock.patch.object(ResourceTransformer, "__init__", return_value=None)
     def test_generate_with_configuration_file(self, mock_init, mock_process):