YAML syntax error when string contains a colon + space #2769

Closed
gw0 opened this Issue Apr 24, 2013 · 25 comments

Projects

None yet
@gw0
Contributor
gw0 commented Apr 24, 2013

There is a YAML syntax error if you try to enter a colon followed by a space (": ") inside any string (doesn't seem to matter what if before or after).

$ cat _test.yml

---
- hosts: all
  tasks:
    - debug: msg="foo: bar"

In Ansible 1.2 development branch:

$ ansible-playbook -v _test.yml 
ERROR: Syntax Error while loading YAML script, _test.yml
Note: The error may actually appear before this position: line 4, column 22

  tasks:
    - debug: msg="foo: bar"
                     ^

A use case where this will cause trouble is when using lineinfile module.

@b6d
Contributor
b6d commented Apr 24, 2013

Hi,

as far as I can tell this is malformed YAML (the first quotes in your example do not start a string, they are part of an implicit string).

you can test this online here: https://yaml-online-parser.appspot.com/

@mpdehaan
Contributor

You can quote the YAML string, this is not a bug.

@mpdehaan mpdehaan closed this Apr 24, 2013
@nafg
nafg commented Nov 29, 2013

What is the correct way to write it?

@gw0
Contributor
gw0 commented Nov 29, 2013

I prefer:

- debug: "msg='foo: bar'"
@rdw
rdw commented Jan 21, 2014

I ran into this problem today, and I wanted to document some of the things that don't work for future searchers. This is the first thing I tried and didn't work:

- lineinfile: dest=/etc/aliases insertafter=EOF line=root: {{ admin_email }}

Quoting the pair didn't resolve the YAML syntax error:

- lineinfile: dest=/etc/aliases insertafter=EOF "line=root: {{ admin_email }}"

Nor did single quotes:

- lineinfile: dest=/etc/aliases insertafter=EOF 'line=root: {{ admin_email }}'

Nor does quoting the value only:

- lineinfile: dest=/etc/aliases insertafter=EOF line="root: {{ admin_email }}"

Quoting the entire line passed the YAML syntax check, but failed during execution of the playbook ("this module requires key=value arguments")

- lineinfile: "dest=/etc/aliases insertafter=EOF line=root: {{ admin_email }}"

In the end, I had to quote both the entire line, and the value:

- lineinfile: "dest=/etc/aliases insertafter=EOF line='root: {{ admin_email }}'"

Another tactic that worked was to remove the space after the colon. Might work, depending on the target file:

- lineinfile: dest=/etc/aliases insertafter=EOF line="root:{{ admin_email }}"
@DaveQB
DaveQB commented Mar 6, 2014

I have this problem a lot on ansible 1.4.1

No of those solutions are working for me. I have had to work around it each time.

Right now I have this.

cron: "state=present name='zpool status' minute='30' job='for i in $(/sbin/zpool list -o name  -H) ; do /sbin/zpool status $i|grep -q 'state: ONLINE' || echo error with zpool $i on $(hostname)|mail me ;done'"

The state: ONLINE is what is tripping it up.

I have tried as number of quoting here but nothing gets me past this error.

@DaveQB
DaveQB commented Mar 10, 2014

Using {{':'}} is the only option that worked for me.
All other quoting just did not pass by ansible's standards. Although it did pass YAML checks.

@chicks-net

What a pain! The official docs examples do not work.

Thanks for the myriad of suggestions.

@chetzof
chetzof commented Sep 2, 2014

nothing in official docs about that
thanks!

@gw0
Contributor
gw0 commented Sep 4, 2014

Because having a malformed YAML because of a colon is such a common problem, it would make sense to display a more informative error message describing exactly what is the problem and how it should be fixed (with an example).

@cemo
cemo commented Jan 13, 2015

here is mine:

line="hostname:{{ ' ' }}{{ item.droplet.name }}"
@skozin
skozin commented Feb 15, 2015

UPD: ignore this, it doesn't work.

You can quote just colons:

- debug: msg="foo':' bar"
- lineinfile: "dest=/etc/aliases insertafter=EOF line=root':' {{ admin_email }}"

Yes, it's a pain.

@skozin
skozin commented Feb 15, 2015

The help message is not helpful, unfortunately, because it doesn't take into account the space after colon:

ERROR: Syntax Error while loading YAML script, /path/to/main.yml
Note: The error may actually appear before this position: line 4, column 42

- name: copy some file
  copy: src=file.txt dest='/path/filename: with_space_and_colon.txt'
                                         ^
This one looks easy to fix.  There seems to be an extra unquoted colon in the line
and this is confusing the parser. It was only expecting to find one free
colon. The solution is just add some quotes around the colon, or quote the
entire line after the first colon.

For instance, if the original line was:

    copy: src=file.txt dest=/path/filename:with_colon.txt

It can be written as:

    copy: src=file.txt dest='/path/filename:with_colon.txt'

Or:

    copy: 'src=file.txt dest=/path/filename:with_colon.txt'

I got bitten by this trying to launch my very first playbook, which contained something like debug: msg="TODO: implement this", and I can't say that it was a pleasant experience for a newcomer :)

I propose to reopen this issue until the docs and the help message get fixed.

@n0n3such
n0n3such commented Mar 2, 2015

I ran into this writing my first playbook. Very unpleasant surprise. Does not encourage the use of ansible. In general I find most ansible-playbook error messages less than helpful and more than slightly annoying.

In my case I was able to work around the problem by removing the space following the offending colon character.

@Regner
Regner commented May 31, 2015

For those coming along later reading this, as I just came across this error today, the best solution I have found so far is to format it like this:

    - name: Add deploy user to sudoers.
      lineinfile: >
        dest=/etc/sudoers
        regexp="{{ DEPLOY_USER_NAME }} ALL"
        line="{{ DEPLOY_USER_NAME }} ALL=(ALL) NOPASSWD: ALL"
        state=present
        validate="visudo -cf %s"

Using the greater than symbol tells YAML to accept a multiline string, which also seems to help avoid this issue.

@leopepe
leopepe commented Dec 9, 2015

Had the same problem. I could scape de colons by arraging in a different way the argument parsing to the module:

- name: lininfile change
  debug:
    msg: "foo: bar"
@paulmaunders

I had been battling with the following string for an hour or so...

line="Source11: {{nps_src_bundle}}"

Ansible was complaining that 'We could be wrong, but this one looks like it might be an issue with missing quotes.'

It was fixed by replacing the colon with {{':'}} as @DaveQB had mentioned above

line="Source11{{':'}} {{nps_src_bundle}}"

@paulmaunders

The previous solution was giving me some problems with syntax highlighting so I have used another solution which also works, but without the syntax highlighting issues.

lineinfile: 'dest="~{{build_usr}}/rpmbuild/SPECS/nginx.spec" regexp="^Source11" insertafter="^Source10" line="Source11: {{nps_src_bundle}}"'

Essentially I have just enclosed everything after lineinfile: inside single quotes.

@xezpeleta

Thanks @DaveQB ! I also solve it with {{':'}}

replace: dest=/home/vagrant/parameters.yml.dist regexp='database_user:\smyuser' replace='database_user{{':'}} root'
@dejayc
dejayc commented Mar 17, 2016

I'm glad this "bug" was closed. After all, you wouldn't want something that's encountered so often, and under such reasonable circumstances, to be handled sensibly by Ansible's YAML parser.

Please keep this feature deliberately confusing and broken, as it will help ensure my job security. TIA!

@Zyphrax
Zyphrax commented Mar 28, 2016

This, fairly normal use case, results in a syntax error as well:

name: Setup the app database
command: bundle exec rake db:setup
when: db_server == 'localhost' and db_version.stdout == 'Current version: 0'

My workaround for now is that I extract just the version number by adding awk '{print $NF}' to the db_version shell command. But it is a bit nasty.

@bcoca
Member
bcoca commented Mar 28, 2016

@Zyphrax or you could do this:

when: "db_server == 'localhost' and db_version.stdout == 'Current version: 0'"

@timzhang1
timzhang1 commented Sep 28, 2016 edited

I have the same problem on Ansible 2.1.0 .

when: not "'Number of Peers: 2' in number_of_peers.stdout"
@bitdivine

I love the way the error message says "We could be wrong, but" .. and gives no recourse when they ARE wrong.

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