Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions sdks/python/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [1.23.4] - 2026-02-13

### Changed

- Fixes cases where raising exception classes or exceptions with no message would cause the whole error including stack trace to be converted to an empty string.
- When an error is raised because a workflow has no tasks it now includes the workflows name.
#### Changed
- Python SDK `ClientConfig` token validation now raises `HatchetConfigurationError` instead of `ValueError` for invalid or missing configuration.
- Minor field validators updated to improve clarity and robustness.
- Updated package patch version to include these non-breaking improvements.

Comment on lines +16 to 20
Copy link

Copilot AI Feb 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changelog entry appears to (1) change the heading level from ### Changed to #### Changed (inconsistent with other entries) and (2) replace prior 1.23.4 bullets with new ones that mention changes (e.g., patch version bump / validator updates) that aren’t present in this PR. Please keep the changelog formatting consistent and ensure the 1.23.4 notes accurately reflect the actual code changes in this PR.

Suggested change
#### Changed
- Python SDK `ClientConfig` token validation now raises `HatchetConfigurationError` instead of `ValueError` for invalid or missing configuration.
- Minor field validators updated to improve clarity and robustness.
- Updated package patch version to include these non-breaking improvements.
### Changed
- Documentation-only updates to the changelog; no functional changes to the Python SDK.

Copilot uses AI. Check for mistakes.
## [1.23.3] - 2026-02-12

Expand Down
15 changes: 8 additions & 7 deletions sdks/python/hatchet_sdk/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from pydantic import Field, field_validator, model_validator
from pydantic_settings import BaseSettings, SettingsConfigDict

from hatchet_sdk.exceptions import HatchetConfigurationError
from hatchet_sdk.token import get_addresses_from_jwt, get_tenant_id_from_jwt
from hatchet_sdk.utils.opentelemetry import OTelAttribute

Expand Down Expand Up @@ -48,15 +49,13 @@ class HealthcheckConfig(BaseSettings):
def validate_event_loop_block_threshold_seconds(
cls, value: timedelta | int | float | str
) -> timedelta:
# Settings env vars are strings; interpret as seconds.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's leave this comment

if isinstance(value, timedelta):
return value

if isinstance(value, int | float):
return timedelta(seconds=float(value))

v = value.strip()
# Allow a small convenience suffix, but keep "seconds" as the contract.
if v.endswith("s"):
v = v[:-1].strip()

Expand Down Expand Up @@ -138,11 +137,15 @@ class ClientConfig(BaseSettings):
@model_validator(mode="after")
def validate_token_and_tenant(self) -> "ClientConfig":
if not self.token:
raise ValueError("Token must be set")
raise HatchetConfigurationError(
"HATCHET_CLIENT_TOKEN must be set. "
"Provide it via environment variable or pass token=... to ClientConfig."
)
Comment on lines 139 to +143
Copy link

Copilot AI Feb 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Token validation behavior changed (exception type/message). There are existing tests covering ClientConfig construction, but none assert the error behavior for missing/invalid tokens. Add unit tests that verify missing token and malformed token cases raise the expected configuration error (and, if required for backwards-compat, that it remains a ValueError subclass).

Copilot uses AI. Check for mistakes.

if not self.token.startswith("ey"):
raise ValueError(
f"Token must be a valid JWT. Hint: These are the first few characters of the token provided: {self.token[:5]}"
raise HatchetConfigurationError(
"HATCHET_CLIENT_TOKEN must be a valid JWT. "
f"Received token starting with: '{self.token[:5]}...'"
)
Comment on lines 137 to 149
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Pydantic v2 validators, raising a non-ValueError/TypeError/AssertionError exception typically bypasses normal ValidationError aggregation and will change what callers see when ClientConfig() is constructed. If the intent is to keep Pydantic-style validation errors, make HatchetConfigurationError inherit from ValueError (or use PydanticCustomError); if the intent is to surface a domain-specific exception to users, consider catching ValidationError at the ClientConfig()/Hatchet() construction boundary and rethrowing HatchetConfigurationError there so behavior is explicit and consistent.

Copilot uses AI. Check for mistakes.
Comment on lines 139 to 149
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Token validation now emits a different exception type/message, but there are no unit tests covering the missing-token and invalid-JWT paths. Add coverage in sdks/python/tests/test_client.py asserting the raised exception type (and key parts of the message) for ClientConfig(token="") and ClientConfig(token="not-a-jwt") so regressions are caught.

Copilot uses AI. Check for mistakes.

if not self.tenant_id:
Expand All @@ -152,8 +155,6 @@ def validate_token_and_tenant(self) -> "ClientConfig":

@model_validator(mode="after")
def validate_addresses(self) -> "ClientConfig":
## If nothing is set, read from the token
## If either is set, override what's in the JWT
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's leave these comments

server_url_from_jwt, grpc_broadcast_address_from_jwt = get_addresses_from_jwt(
self.token
)
Comment on lines 156 to 160
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR description notes the change is intentionally scoped to token validation only, but this diff also removes comments describing how validate_addresses derives overrides from the JWT. Either revert the comment-only edits here or adjust the PR description/scope accordingly.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot open a new pull request to apply changes based on this feedback

Expand Down
4 changes: 4 additions & 0 deletions sdks/python/hatchet_sdk/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
from typing import cast


Comment on lines 4 to 5
Copy link

Copilot AI Feb 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HatchetConfigurationError is introduced as a new public exception type, but it isn't re-exported from hatchet_sdk.__init__ (unlike the other exceptions). Consider adding it to the package exports (__init__.py imports / __all__) so users can reliably import it from hatchet_sdk like the rest of the SDK exceptions.

Suggested change
__all__ = [
"HatchetConfigurationError",
"InvalidDependencyError",
"NonRetryableException",
"DedupeViolationError",
"TASK_RUN_ERROR_METADATA_KEY",
"TaskRunError",
"FailedTaskRunExceptionGroup",
"LoopAlreadyRunningError",
"IllegalTaskOutputError",
"LifespanSetupError",
]

Copilot uses AI. Check for mistakes.
class HatchetConfigurationError(ValueError):
"""Raised when required configuration is missing or invalid."""


class InvalidDependencyError(Exception):
pass

Expand Down
Loading