Skip to content

fix: handle small max_templated_field_length safely#59882

Closed
Jeevankumar-s wants to merge 4 commits intoapache:mainfrom
Jeevankumar-s:fix-small-max-templated-field-length
Closed

fix: handle small max_templated_field_length safely#59882
Jeevankumar-s wants to merge 4 commits intoapache:mainfrom
Jeevankumar-s:fix-small-max-templated-field-length

Conversation

@Jeevankumar-s
Copy link
Copy Markdown

Fixes incorrect truncation when [core] max_templated_field_length is set to very small values.

Previously, negative slicing could result in empty or malformed output.
This change ensures truncation always respects the configured maximum length.

Related: #59877

@boring-cyborg
Copy link
Copy Markdown

boring-cyborg bot commented Dec 29, 2025

Congratulations on your first Pull Request and welcome to the Apache Airflow community! If you have any issues or are unsure about any anything please check our Contributors' Guide (https://github.com/apache/airflow/blob/main/contributing-docs/README.rst)
Here are some useful points:

  • Pay attention to the quality of your code (ruff, mypy and type annotations). Our prek-hooks will help you with that.
  • In case of a new feature add useful documentation (in docstrings or in docs/ directory). Adding a new operator? Check this short guide Consider adding an example DAG that shows how users should use it.
  • Consider using Breeze environment for testing locally, it's a heavy docker but it ships with a working Airflow and a lot of integrations.
  • Be patient and persistent. It might take some time to get a review or get the final approval from Committers.
  • Please follow ASF Code of Conduct for all communication including (but not limited to) comments on Pull Requests, Mailing list and Slack.
  • Be sure to read the Airflow Coding style.
  • Always keep your Pull Requests rebased, otherwise your build might fail due to changes not related to your commits.
    Apache Airflow is a community-driven project and together we are making it better 🚀.
    In case of doubts contact the developers at:
    Mailing List: dev@airflow.apache.org
    Slack: https://s.apache.org/airflow-slack

@potiuk
Copy link
Copy Markdown
Member

potiuk commented Dec 29, 2025

LGTM. @amoghrajesh ?

Copy link
Copy Markdown
Contributor

@amoghrajesh amoghrajesh left a comment

Choose a reason for hiding this comment

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

This change also needs to go in https://github.com/astronomer/airflow/blob/main/task-sdk/src/airflow/sdk/execution_time/task_runner.py#L830-L901 which is where things happen at runtime for a task

Comment on lines +31 to +45
def _truncate_rendered_value(rendered: str, max_length: int) -> str:
if max_length <= 0:
return ""

prefix = "Truncated. You can change this behaviour in [core]max_templated_field_length. "
suffix = "..."

if max_length <= len(prefix):
return rendered[:max_length]

available = max_length - len(prefix) - len(suffix)
if available <= 0:
return rendered[:max_length]

return f"{prefix}{rendered[:available]!r}{suffix}"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

While this is good, from a user perspective, if max_length is set to 1, it would just display rendered[0]. I think from a user perspective, we should prioritise communication to user over "correctness". Or the user wont know what happened.

Always better to present problem + solution vs misleading partial result ig

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks for pointing this out.
I agree that showing just a single character can be confusing from a user perspective.
I’ll update the logic so that, even for very small max_templated_field_length values, we prioritize clearly communicating that truncation has occurred rather than returning a misleading partial result.
I’ll also apply the same change in the runtime path (task_runner.py) so the behavior stays consistent.
I’ll push an update shortly.

@Jeevankumar-s Jeevankumar-s requested a review from kaxil as a code owner December 30, 2025 07:05
Copy link
Copy Markdown
Contributor

@amoghrajesh amoghrajesh left a comment

Choose a reason for hiding this comment

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

I have some concerns with this implementation, check review comments for details.

Comment on lines +32 to +51
def _truncate_rendered_value(rendered: str, max_length: int) -> str:
if max_length <= 0:
return ""

prefix = "Truncated. You can change this behaviour in [core]max_templated_field_length. "
suffix = "..."

if max_length <= len(suffix):
return suffix[:max_length]

if max_length <= len(prefix) + len(suffix):
return (prefix + suffix)[:max_length]

available = max_length - len(prefix) - len(suffix)
return f"{prefix}{rendered[:available]}{suffix}"



def _safe_truncate_rendered_value(rendered: Any, max_length: int) -> str:
return _truncate_rendered_value(str(rendered), max_length)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This still doesn't prioritise message first. Take these test cases for example:

[(1, 'test', 'Minimum value'),
 (3, 'test', 'At ellipsis length'),
 (5, 'test', 'Very small'),
 (10, 'password123', 'Small'),
 (20, 'secret_value', 'Small with content'),
 (50, 'This is a test string', 'Medium'),
 (83, 'Hello World', 'At prefix+suffix boundary v1'),
 (84, 'Hello World', 'Just above boundary v1'),
 (86, 'Hello World', 'At overhead boundary v2'),
 (90, 'short', 'Normal case - short string'),
 (100, 'This is a longer string', 'Normal case'),
 (150,
  'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
  'Large max_length, long string'),
 (100, 'None', "String 'None'"),
 (100, 'True', "String 'True'"),
 (100, "{'key': 'value'}", 'Dict-like string'),
 (100, "test's", 'String with apostrophe'),
 (90, '"quoted"', 'String with quotes')]

This is what your function returns:

for max_length, rendered, description in test_cases:
    v1_result = truncate_v1(rendered, max_length)
    print(v1_result)
    
.
...
Trunc
Truncated.
Truncated. You can c
Truncated. You can change this behaviour in [core]
Truncated. You can change this behaviour in [core]max_templated_field_length. He...
Truncated. You can change this behaviour in [core]max_templated_field_length. Hel...
Truncated. You can change this behaviour in [core]max_templated_field_length. Hello...
Truncated. You can change this behaviour in [core]max_templated_field_length. short...
Truncated. You can change this behaviour in [core]max_templated_field_length. This is a longer st...
Truncated. You can change this behaviour in [core]max_templated_field_length. xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...
Truncated. You can change this behaviour in [core]max_templated_field_length. None...
Truncated. You can change this behaviour in [core]max_templated_field_length. True...
Truncated. You can change this behaviour in [core]max_templated_field_length. {'key': 'value'}...
Truncated. You can change this behaviour in [core]max_templated_field_length. test's...
Truncated. You can change this behaviour in [core]max_templated_field_length. "quoted"...

This is what I would expect:

Truncated. You can change this behaviour in [core]max_templated_field_length. ... 
Truncated. You can change this behaviour in [core]max_templated_field_length. ... 
Truncated. You can change this behaviour in [core]max_templated_field_length. ... 
Truncated. You can change this behaviour in [core]max_templated_field_length. ... 
Truncated. You can change this behaviour in [core]max_templated_field_length. ... 
Truncated. You can change this behaviour in [core]max_templated_field_length. ... 
Truncated. You can change this behaviour in [core]max_templated_field_length. ... 
Truncated. You can change this behaviour in [core]max_templated_field_length. ... 
Truncated. You can change this behaviour in [core]max_templated_field_length. 'He'... 
Truncated. You can change this behaviour in [core]max_templated_field_length. 'short'... 
Truncated. You can change this behaviour in [core]max_templated_field_length. 'This is a longer'... 
Truncated. You can change this behaviour in [core]max_templated_field_length. 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'... 
Truncated. You can change this behaviour in [core]max_templated_field_length. 'None'... 
Truncated. You can change this behaviour in [core]max_templated_field_length. 'True'... 
Truncated. You can change this behaviour in [core]max_templated_field_length. "{'key': 'value'}"... 
Truncated. You can change this behaviour in [core]max_templated_field_length. "test's"... 
Truncated. You can change this behaviour in [core]max_templated_field_length. '"quote'... 

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks for the examples. I agree and have updated the logic to always prioritise the truncation message and avoid partial prefix or value output. The results now match the expected outputs you shared.

@Jeevankumar-s Jeevankumar-s marked this pull request as draft January 1, 2026 10:34
@amoghrajesh
Copy link
Copy Markdown
Contributor

@Jeevankumar-s lot of test failures, could you adhere to them before I can look?

@Jeevankumar-s
Copy link
Copy Markdown
Author

@Jeevankumar-s lot of test failures, could you adhere to them before I can look?

Stopped working on this PR since #59999 is actively addressing the issue.

@Jeevankumar-s Jeevankumar-s deleted the fix-small-max-templated-field-length branch January 22, 2026 09:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants