Skip to content

fix(aws): repair the malformed %s in the tag-key "not permitted" message - #3366

Open
Anai-Guo wants to merge 1 commit into
Netflix:masterfrom
Anai-Guo:fix-aws-tag-key-not-permitted-message
Open

fix(aws): repair the malformed %s in the tag-key "not permitted" message#3366
Anai-Guo wants to merge 1 commit into
Netflix:masterfrom
Anai-Guo:fix-aws-tag-key-not-permitted-message

Conversation

@Anai-Guo

@Anai-Guo Anai-Guo commented Sep 6, 2026

Copy link
Copy Markdown

The bug

metaflow/plugins/aws/aws_utils.py::validate_aws_tag rejects a tag key whose
characters fall outside PERMITTED, but the message template lost its %:

if not re.match(PERMITTED, key):
    raise MetaflowException(
        "Key *s* is not permitted. Tags must match pattern: %s" % (key, PERMITTED)
    )

*s* is a literal, so the template has one conversion specifier for two
arguments. The % operation therefore raises

TypeError: not all arguments converted during string formatting

before MetaflowException is ever constructed — the user never sees the
message the code is trying to give them.

Why this is a typo and not intent

The other three raises in the same function all use *%s*, and the value branch
three lines below is the exact structural twin of the broken one:

if not re.match(PERMITTED, value):
    raise MetaflowException(
        "Value *%s* is not permitted. Tags must match pattern: %s"
        % (value, PERMITTED)
    )

Reachability

validate_aws_tag is called on every user-supplied tag from both AWS backends:

  • metaflow/plugins/aws/batch/batch_decorator.py:245
  • metaflow/plugins/aws/step_functions/step_functions_cli.py:384

PERMITTED is [A-Za-z0-9\s\+\-\=\.\_\:\/\@] and is used with re.match, so
any tag key whose first character is outside that class takes the branch —
e.g. --tag "#team=ml".

Verification

Ran validate_aws_tag extracted verbatim from the file (via
ast.get_source_segment, no hand-copying) against a stub MetaflowException,
before and after the one-character change:

case before after
key="#bad-key", value="ok" TypeError: not all arguments converted during string formatting MetaflowException: Key *#bad-key* is not permitted. Tags must match pattern: [A-Za-z0-9\s\+\-\=\.\_\:\/\@]
key="ok", value="#bad-value" MetaflowException: Value *#bad-value* is not permitted. … unchanged
key="a"*129, value="ok" MetaflowException: Tag key *aaa…* is too long. … unchanged
key="ok", value="ok" no raise unchanged

Only the key-not-permitted branch changes.

Why the test suite did not catch it

test/unit/test_aws_util.py::test_validate_aws_tag never passes a
non-permitted key, and it asserts only on a did_raise boolean caught from a
bare except Exception — a TypeError satisfies it just as well as a
MetaflowException. This PR adds a small companion test that asserts the
rendered message for both the key and the value branch; it fails on master
with the TypeError and passes with the fix.

black 25.12.0 (the version pinned in .pre-commit-config.yaml, with the same
-t target list) reports both files unchanged.

Follow-up, deliberately not in this PR: re.match(PERMITTED, key) only tests
the first character, so a#b is accepted. Tightening that to ^[...]+$ is a
behaviour change and belongs in its own PR — happy to open one if you want it.

🤖 Generated with Claude Code

`validate_aws_tag` raises for a tag key that does not match `PERMITTED`, but
the template reads `Key *s* is not permitted...` instead of `Key *%s* ...`.
With only one conversion specifier left for two arguments, the `%` operation
raises `TypeError: not all arguments converted during string formatting`
before `MetaflowException` is ever constructed.

The value branch three lines below is the correct copy (`Value *%s* is not
permitted. Tags must match pattern: %s`), as are the two length checks above.

Reachable from `--tag` on both AWS Batch (`batch_decorator.py`) and Step
Functions (`step_functions_cli.py`): any tag key whose first character is
outside `[A-Za-z0-9\s+\-=._:/@]` hits it and the user sees an opaque
TypeError instead of the intended message.

The existing parametrised test never passes a non-permitted key and swallows
bare `Exception`, so the branch was invisible to it; the added test asserts
the rendered message for both the key and the value branch.

Signed-off-by: Tai An <antai12232931@outlook.com>
@greptile-apps

greptile-apps Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR repairs malformed interpolation in the AWS tag-key validation error and adds focused regression coverage.

  • Changes the invalid-key diagnostic from the literal *s* to the intended *%s*.
  • Verifies that invalid keys and values raise MetaflowException with the offending input rendered in the message.

Confidence Score: 5/5

The PR appears safe to merge; the formatting fix is narrowly scoped and covered by a regression test.

The corrected template has one conversion specifier for each supplied argument, preserving validation behavior while restoring the intended exception, and no actionable defects remain.

Important Files Changed

Filename Overview
metaflow/plugins/aws/aws_utils.py Corrects the invalid AWS tag-key message so formatting produces the intended MetaflowException.
test/unit/test_aws_util.py Adds regression tests covering exception type and rendered prefixes for invalid tag keys and values.

Reviews (1): Last reviewed commit: "fix(aws): repair the malformed %s in the..." | Re-trigger Greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant