Power Automate: base64ToString function

Power Automate: base64ToString function

by: Manuel 11 min read 0 comments Save

Sooner or later a Power Automate Flow hands you a wall of letters and numbers ending in an equals sign, and none of it means anything. That's base64, and the "base64ToString" function is how you turn it back into words you can read. You give it the encoded string, it gives you the text. That's the whole contract.

It's the mirror image of the base64 function, which goes the other way. File contents, HTTP payloads, and webhook bodies are the places you'll meet it most, because those arrive encoded far more often than people expect. Let's look at how it works, and at the two or three places where its behavior surprises people.

Where to find it?

You can use the function anywhere an expression is supported. In practice it shows up inside a Compose action, an Initialize variable action, or right before a Parse JSON action when the JSON you want to parse arrived encoded.

Don't confuse it with "base64ToBinary"

Both decode base64, but they hand back different things. "base64ToString" gives you text you can read, search, and split. The base64ToBinary function gives you a binary payload meant for an action that expects file content. If you feed a PDF through "base64ToString", you will get a screen of garbage, because a PDF was never text to begin with.

Usage

The "base64ToString" function takes exactly one required parameter and nothing else:

base64ToString('<value>')
Parameter Required Type Description
value Yes String The base64-encoded string to decode

The return value is a String, the decoded text version of whatever was encoded. There is no second parameter, no encoding option, and no format switch. The function does one job.

Basic example

The example Microsoft leads with is the shortest one possible:

base64ToString('aGVsbG8=')

That returns hello. Round-tripping shows the symmetry nicely, since base64('hello') returns aGVsbG8=, and feeding that straight back in gets you where you started:

base64ToString(base64('hello'))

Decoding file content

This is the common case, and it's also where most people trip. The content that file actions return is not a bare string, it's an object with a $content-type property holding the MIME type and a $content property holding the actual base64. You have to reach into $content yourself:

base64ToString(body('Get_file_content')?['$content'])

Let's break that down:

  • body('Get_file_content') reads the output of the SharePoint Get File content action.
  • ?['$content'] safely reaches the base64 string inside the file object. The question mark means a missing property returns null rather than blowing up the Flow.
  • base64ToString(...) decodes that string into readable text.

Decoding a webhook payload

When a When an HTTP request is received trigger receives a payload with an encoded field, the pattern is the same:

base64ToString(triggerBody()?['payload'])

The triggerBody function gets the request body, ?['payload'] pulls the encoded field, and "base64ToString" makes it legible.

Decoding straight into an object

Decoding gives you text, and text is not JSON. If the encoded content was a JSON document and you want to reach into its properties, wrap the result in the json function:

json(base64ToString(triggerBody()?['payload']))?['status']

Decoding eyJzdGF0dXMiOiJBcHByb3ZlZCIsImlkIjo0Mn0= gives you the text {"status":"Approved","id":42}, and the json function turns that text into something ?['status'] can actually read, which returns Approved.

Real-world examples

Reading a CSV before you loop over it

Joana drops a file into a library and a Flow has to work through the rows. Fetch it with the SharePoint Get file content using path action, then decode and split:

split(base64ToString(body('Get_file_content_using_path')?['$content']), decodeUriComponent('%0A'))

The split function breaks the decoded text on the newline character and hands you an array of rows.

Peeking at what a system actually sent you

An external service posts to your Flow and swears the body is correct. Drop a Compose action in with nothing but the decode in it, and read the run history:

base64ToString(triggerBody()?['data'])

One action, no side effects, and the argument about who sent what ends immediately.

Checking a decoded file for a marker

Before writing a file onward with the SharePoint Create File action, Manuel wants to be sure the header row is present. Decode once into a variable, then test it with the contains function:

contains(variables('DecodedFile'), 'Name,Amount')

Non-intuitive behaviors

Let's look at the behaviors that catch people off guard with the "base64ToString" function.

Power Automate often decodes for you already

Microsoft's own documentation is blunt about this. The platform performs base64 encoding and decoding implicitly in many places, so the manual call you're about to write may not be needed at all. The same note warns that using the encoding functions anyway can produce unexpected rendering behavior in the designer.

Check the raw output of the previous action first. If you can already read the content in the run history, you have nothing to decode, and stacking "base64ToString" on top of an already decoded string is how you get a decode error on data that was never broken.

It always assumes UTF-8

There is no character set parameter, and the function reads the decoded bytes as UTF-8. Text that was originally saved as ANSI (Windows-1252) or ISO 8859 decodes into replacement characters wherever an accent used to be, so Olá comes back looking wrong and there is no flag to fix it.

The community idea asking for a character set parameter is still open, so there is no in-product workaround. Either the source system produces UTF-8, or you convert the file's encoding before it reaches the Flow. A per-character replace function patch works for a known, small set of accents, and falls apart for anything else.

A byte order mark rides along invisibly

UTF-8 files exported from Windows tools frequently start with a byte order mark. It survives the decode, so the first row of your decoded CSV carries an invisible character before the first column name. Comparisons against that first column then fail for no reason you can see on screen.

The startsWith function returning false on text that visibly starts with the right word is the usual tell. Strip it before comparing, or use the contains function instead of an exact match.

Binary in, garbage out, no error

Decoding a PDF, an image, or a spreadsheet does not fail. It succeeds and returns a long string of nonsense, because the function faithfully turned those bytes into characters and those bytes were never characters. The Flow carries on and the problem surfaces three actions later, somewhere unrelated. Only decode to a string when the original content genuinely was text.

"decodeBase64" still works, but it's deprecated

There's an older function called "decodeBase64" that does the same job. Microsoft has deprecated it and states plainly that "base64ToString" is the preferred choice. Old Flows and old blog posts are full of it, so you'll meet it, but there's no reason to write it into anything new.

Limitations

It cannot decode URL-safe base64

JWTs and many web APIs use the URL-safe base64 variant, which swaps + for - and / for _, and usually drops the trailing = padding. The "base64ToString" function only understands the standard alphabet, so those strings fail. Microsoft's function list has no URL-safe decoder of any kind, and the community idea asking for one is still open.

The fix is to normalize the string yourself before decoding, using replace for the alphabet and concat to restore the padding. Split that work across a few Compose actions rather than nesting it all into one unreadable line.

There is no encoding parameter

You get UTF-8 and nothing else. No code page, no character set argument, no fallback behavior to configure. Convert the file to UTF-8 before it reaches the Flow, because the source system is the only place the encoding can still be changed.

It only accepts a string

Pass an object and the expression fails outright rather than coercing. This matters because file content and several connector outputs are objects that look like plain strings in the designer. Reach into the object with ?['$content'] and hand that string to the function instead.

The result is text, not structure

Decoding JSON gives you a JSON-shaped string, which is not the same as an object. Reaching into it with ?['property'] returns nothing until you pass it through the json function or a Parse JSON action.

Expression size limits

As with every Power Automate expression, you have a ceiling of 8,192 characters. That's the expression, not the data, so decoding a large file is fine while pasting a large base64 literal into the editor is not.

Troubleshooting Common Errors

The template language function 'base64ToString' expects its parameter to be a string. The provided value is of type 'Object'

Cause: You passed the whole file content object instead of the base64 inside it. The dynamic content chip labeled "File Content" is an object with $content-type and $content properties, and the designer gives no hint of that.

Solution: Reach into $content explicitly.

base64ToString(body('Get_file_content')?['$content'])

The decoded text is full of question marks or diamond characters

Cause: The source was not UTF-8. ANSI and ISO 8859 files lose every accented character on the way through, because the function has no way to know which code page produced them.

Solution: Fix the encoding at the source, saving or exporting the file as UTF-8 before the Flow touches it. If you only ever see a handful of known characters, a chain of replace calls can patch them, but treat that as a last resort rather than a design.

The decode fails on a token that looks like valid base64

Cause: It's URL-safe base64, most likely a JWT segment. The - and _ characters are not in the standard alphabet, and the padding has usually been stripped.

Solution: Translate the alphabet first, then restore the padding based on the length.

replace(replace(triggerBody()?['token'], '-', '+'), '_', '/')

Work out the padding from the length of that normalized string, using the length function and the mod function, then append the right number of = characters with concat before decoding.

The expression returns nothing at all

Cause: The property you're reading doesn't exist, and the ? in your safe navigation is doing exactly what it promised, handing back a null. A renamed action or a slightly different payload shape is usually behind it.

Solution: Compose the raw property on its own and look at it in the run history before decoding it. The empty function inside a Condition action turns that into a check the Flow can make on its own.

empty(body('Get_file_content')?['$content'])

Recommendations

Here are some things to keep in mind when using the "base64ToString" function.

Look at the raw data before you decode it

Most "base64ToString" problems are solved by reading the previous action's output first. If it's already legible, the platform decoded it for you and your expression is the thing breaking it.

Decode once into a variable

If the decoded text is needed more than once, decode it a single time into an Initialize variable action and reference that variable everywhere else with the Variables function. You decode a large file once instead of five times, and there's one action to look at when it goes wrong.

Always use safe navigation

Write ?['$content'], never ['$content']. When a payload arrives without the property, the safe version hands you a null you can test for, and the other one fails the run with an error that points at your expression rather than at the missing data.

Keep string and binary decoding apart

Ask what the content was before it got encoded. Text goes through "base64ToString", and anything that was a file goes through the base64ToBinary function or gets passed along still encoded. Decoding a PDF into a string never throws an error, which is precisely what makes it dangerous. If the distinction is new to you, Understanding Binary and Base64 in Power Automate walks through it properly.

Never build a base64 literal by hand

Encoding with the base64 function and decoding it back in the same breath is a fine way to prove a pipeline works. Pasting a base64 blob you generated on some website into an expression is not, because it eats into your expression limit and nobody, including you in six months, will know what it says.

Always add a comment

Adding a comment will help others understand your expression. Say what the encoded content actually is and where it came from, because base64ToString(body('HTTP')?['$content']) tells the next person how you decoded it and nothing at all about what they're looking at.

Final Thoughts

The "base64ToString" function is a one-parameter function with a one-sentence job, and almost every problem people have with it comes from the data rather than the function. Remember that it wants a string and not the object wrapped around it, that it speaks UTF-8 and nothing else, and that Power Automate has often decoded the content before you got there. Get those three straight, and it will hand you your text back exactly as you left it.

Sources

Back to the Power Automate Function Reference

Photo by Lai Man Nung on Unsplash

Comments

Spotted a mistake or have a better approach? Let me know. I read and reply to every one.

💬

No comments yet

Be the first to share your thoughts on this article!

Leave a Comment

All comments are reviewed for spam before being displayed 5000 left
Replying to