How to Parse an ARN in Python
Part of the AWS Toolkitpartition, service, region, account_id, resource = arn.split(":", 5)[1:]maxsplit=5 caps it at six pieces — the sixth absorbs every remaining colon, no rejoin needed
Explanation
An ARN has six colon-separated fields, but the resource field itself isn't guaranteed to be colon-free — a Lambda function version ARN packs a third piece into it:
arn:aws:lambda:us-east-1:123456789012:function:my-function:1Plain arn.split(":") gives you eight elements here, not six, so indexing by position (parts[5]) grabs only "function" and silently drops my-function:1. Python's str.split has a cleaner fix built in than reaching for a rejoin: pass a maxsplit argument.
partition, service, region, account_id, resource = arn.split(":", 5)[1:]maxsplit=5 caps the split at five colons, producing at most six elements — the sixth one absorbs everything left over, colons included, with no separate rejoin step needed the way a language without a maxsplit argument would require. Applied to the Lambda ARN above, the last element comes back as the full "function:my-function:1", untouched.
The same colons-in-the-resource trap applies to a hand-written regex. A pattern using ([^:]+) for every group looks reasonable, but [^:] explicitly excludes colons — that group won't match the Lambda ARN at all, not even partially. Use a greedy (.+) for the final group instead, since its job is to capture the rest of the string, colons included.
region and account_id can legitimately come back as empty strings, not missing — IAM and S3 ARNs omit one or both. Check == "", not is None, when deciding whether a field was actually provided; a present-but-empty field still shows up as an empty string from split.
For the same technique in JavaScript — where split has no maxsplit argument, so a rejoin is required instead — see How to Parse an ARN, or in Go or Java, see How to Parse an ARN in Go and How to Parse an ARN in Java for a similar count-based split with a sharper failure mode. For the full field-by-field breakdown of a specific ARN, see ARN Parser.
Valid examples
'arn:aws:iam::123456789012:user/john'.split(':', 5) → ['arn', 'aws', 'iam', '', '123456789012', 'user/john']Only six pieces total — maxsplit doesn't change anything when there's nothing extra to protect.
'arn:aws:lambda:us-east-1:123456789012:function:my-function:1'.split(':', 5) → [..., 'function:my-function:1']The last element absorbs both remaining colons instead of being cut off at the first one.
'arn:aws:s3:::amzn-s3-demo-bucket/Development/*'.split(':', 5) → ['arn', 'aws', 's3', '', '', 'amzn-s3-demo-bucket/Development/*']region and account_id both come back as empty strings for an S3 bucket ARN — present, just empty.
Invalid examples
arn.split(':')[5] # 'function', not 'function:my-function:1'Splitting with no maxsplit and indexing by position — the Lambda ARN above has 8 parts, not 6, so [5] grabs the wrong piece.
re.match(r"^arn:([^:]+):([^:]+):([^:]*):([^:]*):([^:]+)$", arn)Every group uses [^:]+ — returns None for the Lambda ARN, since its resource part contains colons the pattern explicitly excludes.
if region is None: ...Checking for None instead of an empty string — split(':', 5) always returns a string for a present field, even an empty one, like IAM's region.