Skip to content

exceptions

napt.exceptions

Exception hierarchy for NAPT.

This module defines a custom exception hierarchy for distinguishing between different types of errors. All exceptions inherit from NAPTError, allowing callers to catch all NAPT errors with a single except clause if needed.

NAPTError

Bases: Exception

Base exception for all NAPT errors.

All NAPT-specific exceptions inherit from this class, allowing callers to catch all NAPT errors with a single except clause if needed.

Source code in napt/exceptions.py
class NAPTError(Exception):
    """Base exception for all NAPT errors.

    All NAPT-specific exceptions inherit from this class, allowing callers
    to catch all NAPT errors with a single except clause if needed.
    """

    pass

ConfigError

Bases: NAPTError

Raised for configuration-related errors.

This exception is raised when there are problems with:

  • YAML parse errors (syntax errors, invalid structure)
  • Missing required configuration fields (e.g., no apps defined, missing 'discovery.strategy' field)
  • Invalid strategy configuration (unknown strategy name, invalid strategy parameters)
  • Missing recipe files (file not found)
  • Recipe validation failures (invalid recipe structure, missing required app fields)
Example

Catching configuration errors:

from napt.exceptions import ConfigError

try:
    config = load_effective_config(Path("invalid.yaml"))
except ConfigError as e:
    print(f"Config error: {e}")

Source code in napt/exceptions.py
class ConfigError(NAPTError):
    """Raised for configuration-related errors.

    This exception is raised when there are problems with:

    - YAML parse errors (syntax errors, invalid structure)
    - Missing required configuration fields (e.g., no apps defined, missing
        'discovery.strategy' field)
    - Invalid strategy configuration (unknown strategy name, invalid strategy
        parameters)
    - Missing recipe files (file not found)
    - Recipe validation failures (invalid recipe structure, missing required
        app fields)

    Example:
        Catching configuration errors:
            ```python
            from napt.exceptions import ConfigError

            try:
                config = load_effective_config(Path("invalid.yaml"))
            except ConfigError as e:
                print(f"Config error: {e}")
            ```
    """

    pass

NetworkError

Bases: NAPTError

Raised for network/download-related errors.

This exception is raised when there are problems with:

  • Download failures (HTTP errors, connection timeouts, network unreachable)
  • API call failures (GitHub API errors, JSON API endpoint failures, authentication issues)
  • Network-related version extraction errors (API response parsing failures)
Example

Catching network errors:

from napt.exceptions import NetworkError

try:
    result = discover_recipe(Path("recipe.yaml"), Path("./downloads"))
except NetworkError as e:
    print(f"Network error: {e}")

Source code in napt/exceptions.py
class NetworkError(NAPTError):
    """Raised for network/download-related errors.

    This exception is raised when there are problems with:

    - Download failures (HTTP errors, connection timeouts, network
        unreachable)
    - API call failures (GitHub API errors, JSON API endpoint failures,
        authentication issues)
    - Network-related version extraction errors (API response parsing
        failures)

    Example:
        Catching network errors:
            ```python
            from napt.exceptions import NetworkError

            try:
                result = discover_recipe(Path("recipe.yaml"), Path("./downloads"))
            except NetworkError as e:
                print(f"Network error: {e}")
            ```
    """

    pass

PackagingError

Bases: NAPTError

Raised for packaging/build-related errors.

This exception is raised when there are problems with:

  • Build failures (PSADT template processing errors, file operations, directory creation failures)
  • Missing build tools (IntuneWinAppUtil.exe not found, PSADT template missing)
  • MSI extraction errors (failed to read MSI ProductVersion, unsupported MSI format)
  • Packaging operations (IntuneWinAppUtil.exe execution failures, invalid build directory structure)
  • Malformed .intunewin files (invalid ZIP structure, missing Detection.xml, missing required encryption fields)
Example

Catching packaging errors:

from napt.exceptions import PackagingError

try:
    build_package(Path("recipe.yaml"), Path("./builds"))
except PackagingError as e:
    print(f"Packaging error: {e}")

Source code in napt/exceptions.py
class PackagingError(NAPTError):
    """Raised for packaging/build-related errors.

    This exception is raised when there are problems with:

    - Build failures (PSADT template processing errors, file operations,
        directory creation failures)
    - Missing build tools (IntuneWinAppUtil.exe not found, PSADT template
        missing)
    - MSI extraction errors (failed to read MSI ProductVersion, unsupported
        MSI format)
    - Packaging operations (IntuneWinAppUtil.exe execution failures, invalid
        build directory structure)
    - Malformed .intunewin files (invalid ZIP structure, missing Detection.xml,
        missing required encryption fields)

    Example:
        Catching packaging errors:
            ```python
            from napt.exceptions import PackagingError

            try:
                build_package(Path("recipe.yaml"), Path("./builds"))
            except PackagingError as e:
                print(f"Packaging error: {e}")
            ```
    """

    pass

StateError

Bases: NAPTError

Raised for persisted-state integrity errors.

This exception is raised when NAPT's own persisted state (the deployment state files under state/) is unreadable or invalid:

  • Corrupted deployment state files (invalid JSON)
  • Invalid deployment state fields (e.g., an unparseable ring entered_at timestamp)

Deployment state is authoritative and never auto-replaced; the error message says how to recover.

Example

Catching state errors:

from napt.exceptions import StateError

try:
    state = load_deployment_state(path)
except StateError as e:
    print(f"State error: {e}")

Source code in napt/exceptions.py
class StateError(NAPTError):
    """Raised for persisted-state integrity errors.

    This exception is raised when NAPT's own persisted state (the
    deployment state files under ``state/``) is unreadable or invalid:

    - Corrupted deployment state files (invalid JSON)
    - Invalid deployment state fields (e.g., an unparseable ring
        ``entered_at`` timestamp)

    Deployment state is authoritative and never auto-replaced; the error
    message says how to recover.

    Example:
        Catching state errors:
            ```python
            from napt.exceptions import StateError

            try:
                state = load_deployment_state(path)
            except StateError as e:
                print(f"State error: {e}")
            ```
    """

    pass

AuthError

Bases: NAPTError

Raised for authentication and authorization errors.

This exception is raised when there are problems with:

  • No credential available (no service principal / OIDC environment and no session from 'napt auth login')
  • Graph API 401 Unauthorized or 403 Forbidden responses
  • Interactive sign-in failure, timeout, or cancellation
  • A cached sign-in session that can no longer be refreshed
Example

Catching auth errors:

from napt.exceptions import AuthError

try:
    result = upload_package(Path("recipe.yaml"))
except AuthError as e:
    print(f"Auth error: {e}")

Source code in napt/exceptions.py
class AuthError(NAPTError):
    """Raised for authentication and authorization errors.

    This exception is raised when there are problems with:

    - No credential available (no service principal / OIDC environment and
        no session from 'napt auth login')
    - Graph API 401 Unauthorized or 403 Forbidden responses
    - Interactive sign-in failure, timeout, or cancellation
    - A cached sign-in session that can no longer be refreshed

    Example:
        Catching auth errors:
            ```python
            from napt.exceptions import AuthError

            try:
                result = upload_package(Path("recipe.yaml"))
            except AuthError as e:
                print(f"Auth error: {e}")
            ```
    """

    pass

NotModifiedError

Bases: Exception

Raised when a conditional HTTP request returns 304 Not Modified.

This exception is raised when download_file() receives HTTP 304, meaning the server has confirmed that the remote content has not changed since the last request. The function is expected to return a file on disk, and with a 304 response there is no file to return, so it raises instead.

Inherits from Exception (not NAPTError) so that broad catches of all NAPT errors do not suppress 304 responses. Callers that supply an ETag must handle this explicitly.

Example

Handling a conditional download:

from napt.exceptions import NotModifiedError

try:
    result = download_file(url, dest, etag=cached_etag)
except NotModifiedError:
    # Server confirmed content unchanged, use the cached file
    pass

Source code in napt/exceptions.py
class NotModifiedError(Exception):
    """Raised when a conditional HTTP request returns 304 Not Modified.

    This exception is raised when download_file() receives HTTP 304, meaning
    the server has confirmed that the remote content has not changed since the
    last request. The function is expected to return a file on disk, and with
    a 304 response there is no file to return, so it raises instead.

    Inherits from Exception (not NAPTError) so that broad catches of all NAPT
    errors do not suppress 304 responses. Callers that supply an ETag must
    handle this explicitly.

    Example:
        Handling a conditional download:
            ```python
            from napt.exceptions import NotModifiedError

            try:
                result = download_file(url, dest, etag=cached_etag)
            except NotModifiedError:
                # Server confirmed content unchanged, use the cached file
                pass
            ```
    """

    pass