Apache Airflow version
main (development)
What happened?
airflowctl connections import fails with a cryptic Pydantic ValidationError when the input JSON does not include an extra field for a connection.
The root cause is in connection_command.py:57:
extra=v.get("extra", {}),
When the extra key is absent from the JSON, v.get("extra", {}) returns {} (an empty dict). However, the ConnectionBody model defines extra as str | None (line 226 in generated.py):
extra: Annotated[str | None, Field(title="Extra")] = None
Pydantic rejects the dict with: Input should be a valid string [type=string_type, input_value={}, input_type=dict]
The fix is straightforward: change v.get("extra", {}) to v.get("extra"), which returns None when the key is absent — matching the model's str | None type.
What you think should happen instead?
A connection JSON without an extra field should import successfully, since extra is an optional field (str | None = None) in the model.
How to reproduce
# Create a minimal connection JSON without 'extra' field
echo '{"my_conn": {"conn_type": "postgres", "host": "localhost", "port": 5432}}' > /tmp/test_conn.json
airflowctl connections import /tmp/test_conn.json
Actual result:
Failed to import connections: 1 validation error for ConnectionBody
extra
Input should be a valid string [type=string_type, input_value={}, input_type=dict]
Expected result:
Successfully imported 1 connection(s)
Verification (standalone Pydantic test confirming the behavior):
from pydantic import BaseModel, Field, ConfigDict
from typing import Annotated, Optional
class ConnectionBody(BaseModel):
model_config = ConfigDict(extra="forbid")
connection_id: Annotated[str, Field()]
conn_type: Annotated[str, Field()]
extra: Annotated[Optional[str], Field()] = None
# FAILS - current behavior (default={})
ConnectionBody(connection_id="test", conn_type="postgres", extra={})
# => ValidationError: Input should be a valid string
# WORKS - correct behavior (default=None)
ConnectionBody(connection_id="test", conn_type="postgres", extra=None)
# => OK
Operating System
Linux
Versions of Apache Airflow Providers
N/A
Deployment
Other
Deployment details
Breeze development environment
Anything else?
The extra field in Airflow connections stores a JSON string (e.g., '{"ssl": true}'). When omitted from the import JSON, the default should be None, not {}.
Code reference — airflow-ctl/src/airflowctl/ctl/commands/connection_command.py:49-61
Are you willing to submit PR?
Code of Conduct
Apache Airflow version
main (development)
What happened?
airflowctl connections importfails with a cryptic Pydantic ValidationError when the input JSON does not include anextrafield for a connection.The root cause is in
connection_command.py:57:When the
extrakey is absent from the JSON,v.get("extra", {})returns{}(an empty dict). However, theConnectionBodymodel definesextraasstr | None(line 226 ingenerated.py):Pydantic rejects the dict with:
Input should be a valid string [type=string_type, input_value={}, input_type=dict]The fix is straightforward: change
v.get("extra", {})tov.get("extra"), which returnsNonewhen the key is absent — matching the model'sstr | Nonetype.What you think should happen instead?
A connection JSON without an
extrafield should import successfully, sinceextrais an optional field (str | None = None) in the model.How to reproduce
Actual result:
Expected result:
Verification (standalone Pydantic test confirming the behavior):
Operating System
Linux
Versions of Apache Airflow Providers
N/A
Deployment
Other
Deployment details
Breeze development environment
Anything else?
The
extrafield in Airflow connections stores a JSON string (e.g.,'{"ssl": true}'). When omitted from the import JSON, the default should beNone, not{}.Code reference —
airflow-ctl/src/airflowctl/ctl/commands/connection_command.py:49-61Are you willing to submit PR?
Code of Conduct