New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

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

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

This comment has been minimized.

Show comment
Hide comment
@b6d

b6d Apr 24, 2013

Contributor

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/

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

This comment has been minimized.

Show comment
Hide comment
@mpdehaan

mpdehaan Apr 24, 2013

Contributor

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

Contributor

mpdehaan commented Apr 24, 2013

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

@mpdehaan mpdehaan closed this Apr 24, 2013

@nafg

This comment has been minimized.

Show comment
Hide comment
@nafg

nafg Nov 29, 2013

What is the correct way to write it?

nafg commented Nov 29, 2013

What is the correct way to write it?

@gw0

This comment has been minimized.

Show comment
Hide comment
@gw0

gw0 Nov 29, 2013

Contributor

I prefer:

- debug: "msg='foo: bar'"
Contributor

gw0 commented Nov 29, 2013

I prefer:

- debug: "msg='foo: bar'"
@rdw

This comment has been minimized.

Show comment
Hide comment
@rdw

rdw 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 }}"

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

This comment has been minimized.

Show comment
Hide comment
@DaveQB

DaveQB 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 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

This comment has been minimized.

Show comment
Hide comment
@DaveQB

DaveQB 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.

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

This comment has been minimized.

Show comment
Hide comment
@chicks-net

chicks-net Apr 28, 2014

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

Thanks for the myriad of suggestions.

chicks-net commented Apr 28, 2014

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

Thanks for the myriad of suggestions.

@chetzof

This comment has been minimized.

Show comment
Hide comment
@chetzof

chetzof Sep 2, 2014

nothing in official docs about that
thanks!

chetzof commented Sep 2, 2014

nothing in official docs about that
thanks!

@gw0

This comment has been minimized.

Show comment
Hide comment
@gw0

gw0 Sep 4, 2014

Contributor

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).

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

This comment has been minimized.

Show comment
Hide comment
@cemo

cemo Jan 13, 2015

here is mine:

line="hostname:{{ ' ' }}{{ item.droplet.name }}"

cemo commented Jan 13, 2015

here is mine:

line="hostname:{{ ' ' }}{{ item.droplet.name }}"
@skozin

This comment has been minimized.

Show comment
Hide comment
@skozin

skozin 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 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

This comment has been minimized.

Show comment
Hide comment
@skozin

skozin 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.

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

This comment has been minimized.

Show comment
Hide comment
@n0n3such

n0n3such 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.

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.

@srgvg

This comment has been minimized.

Show comment
Hide comment
Member

srgvg commented Mar 2, 2015

@regner

This comment has been minimized.

Show comment
Hide comment
@regner

regner 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.

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.

@bkendall bkendall referenced this issue Nov 9, 2015

Merged

San 2841 #192

@leopepe

This comment has been minimized.

Show comment
Hide comment
@leopepe

leopepe 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"

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

This comment has been minimized.

Show comment
Hide comment
@paulmaunders

paulmaunders Dec 11, 2015

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 commented Dec 11, 2015

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

This comment has been minimized.

Show comment
Hide comment
@paulmaunders

paulmaunders Dec 11, 2015

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.

paulmaunders commented Dec 11, 2015

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

This comment has been minimized.

Show comment
Hide comment
@xezpeleta

xezpeleta Dec 18, 2015

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

replace: dest=/home/vagrant/parameters.yml.dist regexp='database_user:\smyuser' replace='database_user{{':'}} root'

xezpeleta commented Dec 18, 2015

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

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

This comment has been minimized.

Show comment
Hide comment
@dejayc

dejayc 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!

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

This comment has been minimized.

Show comment
Hide comment
@Zyphrax

Zyphrax 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.

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

This comment has been minimized.

Show comment
Hide comment
@bcoca

bcoca Mar 28, 2016

Member

@Zyphrax or you could do this:

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

Member

bcoca commented Mar 28, 2016

@Zyphrax or you could do this:

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

@timzhang1

This comment has been minimized.

Show comment
Hide comment
@timzhang1

timzhang1 Sep 28, 2016

I have the same problem on Ansible 2.1.0 .

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

timzhang1 commented Sep 28, 2016

I have the same problem on Ansible 2.1.0 .

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

This comment has been minimized.

Show comment
Hide comment
@bitdivine

bitdivine Jan 30, 2017

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

bitdivine commented Jan 30, 2017

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

@tedder

This comment has been minimized.

Show comment
Hide comment
@tedder

tedder Jul 14, 2017

Contributor

{{':'}} is deprecated for a 'when' clause in Ansible2. ':' isn't sufficient. Not sure how to fix now. I changed my content upstream, but that isn't always possible.

Contributor

tedder commented Jul 14, 2017

{{':'}} is deprecated for a 'when' clause in Ansible2. ':' isn't sufficient. Not sure how to fix now. I changed my content upstream, but that isn't always possible.

@j127

This comment has been minimized.

Show comment
Hide comment
@j127

j127 Nov 14, 2017

This should have a better error message. It took me a couple of hours to find a solution.

"You can't have a space after a string unless you use a multi-line quote or quote it..." (or whatever will solve it -- I removed the space).

j127 commented Nov 14, 2017

This should have a better error message. It took me a couple of hours to find a solution.

"You can't have a space after a string unless you use a multi-line quote or quote it..." (or whatever will solve it -- I removed the space).

@mftovey

This comment has been minimized.

Show comment
Hide comment
@mftovey

mftovey Jan 15, 2018

I am using Ansible version 2.3.1.0. I got past this with the following syntax:

  • debug:
    msg: "My message with colon: {{somevar}} - this works for me"

mftovey commented Jan 15, 2018

I am using Ansible version 2.3.1.0. I got past this with the following syntax:

  • debug:
    msg: "My message with colon: {{somevar}} - this works for me"
@jbertozzi

This comment has been minimized.

Show comment
Hide comment
@jbertozzi

jbertozzi Feb 6, 2018

I had the issue in a filter. I used '\s' as workaround:
debug: msg={{key.stdout | regex_replace('^sshPublicKey:\s(.*)$', '\1') }}

jbertozzi commented Feb 6, 2018

I had the issue in a filter. I used '\s' as workaround:
debug: msg={{key.stdout | regex_replace('^sshPublicKey:\s(.*)$', '\1') }}

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