How to fix "jq: error string and number cannot be added" in AWS CloudShell?
Tags: aws, jq, cloudshell
Published: 2023-02-03 21:16:36

---
title: How to fix "jq: error string and number cannot be added" in AWS CloudShell?
published: true
description: How to fix the error caused by jq 'join' in AWS CloudShell?
tags: aws,jq,cloudshell
---

Note: This article is an English translation of my original article, which you can find [here](https://qiita.com/JHashimoto/items/85bf0ecac0d6fea61311).

## Overview

This article describes the causes and solutions to the error when using jq join in AWS CloudShell.

## jq error in AWS CloudShell

This section describes an error that occurs when using jq in AWS CloudShell.

If you try to join an array that contains numbers, you will get `jq: error string and number cannot be added`.

Expected:

```bash
$ echo '["example",0]' | jq 'join(".")'
"example.0"
```

Actual:

```bash
$ echo '["example",0]' | jq 'join(".")'
jq: error (at <stdin>:1): string (".") and number (0) cannot be added
```

## Cause

This section describes the cause of this error.

The version of jq preinstalled in CloudShell is 1.5[^1].

```bash
$ jq --version
jq-1.5
```

[^1]: This is the version at the time of the article submission. It may be upgraded in the future.

A bug in the 1.5 version of join does not convert number types into strings, resulting in this error.

[L1422 - jq/builtin.c at jq-1.5 · stedolan/jq](https://github.com/stedolan/jq/blob/jq-1.5/builtin.c#L1422)

```c
  "def join($x): reduce .[] as $i (null; (.//\"\") + (if . == null then $i else $x + $i end))//\"\";",
```

Note:

Ver 1.6 fixed this bug. You can confirm that in the joined source, which converts the type number to a string with `tostring`.

```bash
def join($x): reduce .[] as $i (null;
            (if .==null then "" else .+$x end) +
            ($i | if type=="boolean" or type=="number" then tostring else .//"" end)
        ) // "";
```

The issue:

{% embed https://github.com/stedolan/jq/issues/1595 %}

## Solution 1

I would describe two means of resolving this error.

First, I explain how to fix it to work with jq1.5.

If you convert the number to a string before passing it to join, it will work as expected in 1.5. And, of course, it also works fine with 1.6.

```bash
$ echo '["example",0]' | jq 'map(.|tostring) | join(".")'
"example.0"
```

## Solution 2

Next, I explain how to install jq1.6 in CloudShell.

However, the yum provided with CloudShell does not upgrade the pre-installed jq[^2], so you will download the binary in an appropriate directory.

[^2]: I confirmed with AWS support.

Note: (about directory persistence) 

Please note that if you place binary files in `/usr/bin`, the files will be deleted when CloudShell is restarted.

If you place the file in your home directory, the data will be persistent, but please note that the file will be deleted when you do not use that CloudShell environment for more than 120 days.

[Service quotas and restrictions for AWS CloudShell - AWS CloudShell](https://docs.aws.amazon.com/cloudshell/latest/userguide/limits.html#persistent-storage-limitations)

### Practical Examples
Here is a concrete example to explanate the solution.

Create an installation directory in your home directory and download the binary. Of course, the directory is arbitrary, but here we assume `jq1.6`.

```bash
cd ~
mkdir jq1.6
cd jq1.6
wget -O jq https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64
chmod +x ./jq 
```

As mentioned earlier, this bug has been Fixed in 1.6, so it works as expected.

```bash
$ ~/jq1.6/jq --version
jq-1.6
$ echo '["example",0]' | ~/jq1.6/jq 'join(".")'
"example.0"
```

It is helpful to set up an alias.

```bash
$ echo "alias jq=~/jq1.6/jq" >> ~/.bashrc
$ . ~/.bashrc  # Reflect the alias in the shell where you are logged in:
$ echo '["example",0]' | jq 'join(".")'
"example.0"
```

### To run as a shell script

Note that when running as a shell script, the login shell environment is not inherited, so the alias is undefined, and it executes with jq 1.5.

`./join.sh`:

```bash:join.sh
#!/bin/bash
echo '["example",0]' | jq 'join(".")'
```

```bash
$ bash ./join.sh 
jq: error (at <stdin>:1): string (".") and number (0) cannot be added
```

In this case, if you specify interactive behavior with the `-i` option, the shell in the execution environment will read `~/.bashrc` and execute the script, as expected.

```bash
$ bash -i ./join.sh 
"example.0"
```

## Conclusion

This section summarizes how to deal with the error when using jq in CloudShell.

I have described two solutions.

Solution 1 has the advantage of not requiring any changes to the CloudShell environment and is portable as it works with both 1.5 and 1.6. [^3]

[^3]: If you have a development PC or other environment where you can install freely, you will likely install the latest version, 1.6.

Solution 2, however, has the advantage of running on 1.6, so it can also handle behaviors other than join error.

One of the changes other than join in 1.6:

[Different behavior when omitting jq arguments](https://shogo82148-github-io.translate.goog/blog/2022/04/25/2022-04-25-jq-program/?_x_tr_sl=ja&_x_tr_tl=en&_x_tr_hl=ja&_x_tr_pto=wapp)

Please use one of these methods depending on your situation.

## Reference

{% embed https://stackoverflow.com/questions/46911763/jq-error-number-and-string-cannot-be-added %}