Windows – Exit /b 0 does not set %errorlevel% to 0

batchcommand lineJenkinswindowswindows-error-reporting

I have a weird behavior wrt setting errorlevel in a batch script to 0.

I am calling a batch script a.bat on a Jenkins job, which in turn calls a second script b.cmd and evaluates the errorlevel after the call:

:: b.cmd
:: some stuff, but relevant is only this:
@echo b errorlevel: %errorlevel%
EXIT /B 0

The "main" script:

:: a.bat
pushd %CD%
cd..

@echo a errorlevel: %errorlevel%

set outputdir=".\some\exisiting\dir"
:: (1)
md %outpurdir%
@echo a errorlevel: %errorlevel%

:: (!)
if "$somevar" = "FOO" ( 
  cd .\WhereBIs

  :: (2)
  call :seterr 0
  @echo a errorlevel: %errorlevel%

  :: (3)
  call b.cmd

  @if %errorlevel% neq 0 (
    @echo a errorlevel: %errorlevel%
    set errmsg=Error calling b
    goto error
  )

  :: more stuff
)

:error
@echo %errmsg%
popd
:: (4)
@echo a errorlevel: %errorlevel%
@if %errorlevel% neq 0 exit %errorlevel%
Exit /B 1

:seterr
exit /b %1

(I borrowed the :seterr stuff from this question)

What seems to happen when I run the Jenkins job:

  1. md returns and errorlevel is set to 1, because the directory already exists.
  2. the call to :seterr does not have the expected effect, errorlevel remains 1
  3. the call to b.cmd completes without problems, errorlevel in b is 0, but after the call errorlevel in a is still 1, which I would definitely not expect after reading the answers to the linked question.
  4. after the jump to :error and call of popd, errorlevel is suddenly reset to 0 – which I would not expect either.

Does anybody have a clue what might be happening here? I did not accidentally set errorlevel manually, so it should be the system variable, not a userdefined one.

Best Answer

You have not shown the entire script. The only possible explanation I am aware of is your code is within a larger parenthesized block of code, possibly part of a FOR loop or an IF condition.

%ERRORLEVEL% is expanded when the line is parsed, and the entire parenthesized block is parsed at the same time. So the ERRORLEVEL that you are seeing must have existed prior to the start of the outermost paranthesis.

You should use delayed expansion if you want to see a changing value within a code block.

Here is a simple demonstration:

@echo off
setlocal enableDelayedExpansion
set var=BEFORE
(
  set var=AFTER
  echo Normal expansion shows value before block started: %var%
  echo Delayed expansion shows the current value: !var!
)

-- OUTPUT --

Normal expansion shows value before block started: BEFORE
Delayed expansion shows the current value: AFTER
Related Question