Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-48258

git client plugin occasionally fails with "text file busy" error

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: Minor Minor
    • git-client-plugin
    • None
    • ubuntu 16.04

      Occasionally I get the following git error early in some of my pipeline builds, but have not been able to reproduce the issue during testing.

      Perhaps the createUnixGitSSH method in CliGitAPIImpl.java should explicitly close the PrintWriter before returning?  Or maybe it just needs to flush the stream, and the script should be executed as "sh tmpfile.sh" instead of "./tmpfile.sh" ?

      using GIT_SSH to set credentials 
       > git ls-remote -h -t git.example.org:/var/git/foo.git # timeout=10
      hudson.plugins.git.GitException: Command "git ls-remote -h -t git.example.org:/var/git/foo.git" returned status code 128:
      stdout: 
      stderr: fatal: cannot exec '/tmp/ssh4044675960910064496.sh': Text file busy
      fatal: unable to fork
      
      	at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.launchCommandIn(CliGitAPIImpl.java:1970)
      	at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.launchCommandWithCredentials(CliGitAPIImpl.java:1689)
      	at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.launchCommandWithCredentials(CliGitAPIImpl.java:1600)
      	at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.launchCommandWithCredentials(CliGitAPIImpl.java:1591)
      	at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.getRemoteReferences(CliGitAPIImpl.java:2785)
      	at jenkins.plugins.git.AbstractGitSCMSource.retrieve(AbstractGitSCMSource.java:708)
      	at jenkins.scm.api.SCMSource.fetch(SCMSource.java:598)
      	at org.jenkinsci.plugins.workflow.libs.SCMSourceRetriever.retrieve(SCMSourceRetriever.java:80)
      	at org.jenkinsci.plugins.workflow.libs.LibraryAdder.retrieve(LibraryAdder.java:153)
      	at org.jenkinsci.plugins.workflow.libs.LibraryAdder.add(LibraryAdder.java:134)
      	at org.jenkinsci.plugins.workflow.libs.LibraryDecorator$1.call(LibraryDecorator.java:125)
      	at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:1065)
      	at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:603)
      	at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:581)
      	at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:558)
      	at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:298)
      	at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:268)
      	at groovy.lang.GroovyShell.parseClass(GroovyShell.java:688)
      	at groovy.lang.GroovyShell.parse(GroovyShell.java:700)
      	at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.doParse(CpsGroovyShell.java:129)
      	at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.reparse(CpsGroovyShell.java:123)
      	at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.parseScript(CpsFlowExecution.java:517)
      	at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.start(CpsFlowExecution.java:480)
      	at org.jenkinsci.plugins.workflow.job.WorkflowRun.run(WorkflowRun.java:269)
      	at hudson.model.ResourceController.execute(ResourceController.java:97)
      	at hudson.model.Executor.run(Executor.java:421)
      org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
      WorkflowScript: Loading libraries failed
      
      1 error
      

          [JENKINS-48258] git client plugin occasionally fails with "text file busy" error

          Mostyn Bramley-Moore created issue -
          Mark Waite made changes -
          Assignee Original: Mark Waite [ markewaite ]

          Mark Waite added a comment -

          The "try with resources" technique used in CliGitAPIImpl has been more reliable (for me at least) than explicit calls to close files. It was used to resolve one or more file handle leaks a few years ago.

          The command that is being called by the plugin is git ls-remote -h -t git.example.org:/var/git/foo.git. The plugin does not execute that shell script directly, but relies on git to execute the shell script. The environment variables set prior to that call refer to the temporary file which was written (and closed) prior to the call of the git command.

          If you find a repeatable way to see the problem, please update the bug report with that information.

          Mark Waite added a comment - The " try with resources " technique used in CliGitAPIImpl has been more reliable (for me at least) than explicit calls to close files. It was used to resolve one or more file handle leaks a few years ago. The command that is being called by the plugin is git ls-remote -h -t git.example.org:/var/git/foo.git . The plugin does not execute that shell script directly, but relies on git to execute the shell script. The environment variables set prior to that call refer to the temporary file which was written (and closed) prior to the call of the git command. If you find a repeatable way to see the problem, please update the bug report with that information.

          Thanks for the tip, I now suspect that this is not a jenkins issue, but a git on NFS issue in my cloud setup.  I created a tmpfs for /tmp in the meantime while I investigate.

           

          Marking this closed.

          Mostyn Bramley-Moore added a comment - Thanks for the tip, I now suspect that this is not a jenkins issue, but a git on NFS issue in my cloud setup.  I created a tmpfs for /tmp in the meantime while I investigate.   Marking this closed.
          Mostyn Bramley-Moore made changes -
          Resolution New: Not A Defect [ 7 ]
          Status Original: Open [ 1 ] New: Resolved [ 5 ]

          Magnus Bäck added a comment - - edited

          FWIW one of our users just experienced a very similar error; just a different path and a for a fetch operation rather than ls-remote. Running Jenkins 2.60.3 with 2.5.0 of the git client plugin. No NFS shares are involved in our case, just plain ext4 partitions mounted into the Docker container where Jenkins runs.

          git fetch --tags --progress origin +refs/heads/:refs/remotes/origin/
           hudson.plugins.git.GitException: Command "git fetch --tags --progress origin +refs/heads/:refs/remotes/origin/" returned status code 128:
           stdout: 
           stderr: fatal: cannot exec '/srv/jenkins/caches/git-a67f10a9b25be4c33f1701c0caff217e@tmp/ssh4168691036775888323.sh': Text file busy
           fatal: unable to fork
          at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.launchCommandIn(CliGitAPIImpl.java:1924)
           at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.launchCommandWithCredentials(CliGitAPIImpl.java:1643)
           at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.access$300(CliGitAPIImpl.java:71)
           at org.jenkinsci.plugins.gitclient.CliGitAPIImpl$1.execute(CliGitAPIImpl.java:352)
           at jenkins.plugins.git.AbstractGitSCMSource.doRetrieve(AbstractGitSCMSource.java:344)
           at jenkins.plugins.git.AbstractGitSCMSource.retrieve(AbstractGitSCMSource.java:524)
           at jenkins.scm.api.SCMSource.fetch(SCMSource.java:598)
           at org.jenkinsci.plugins.workflow.libs.SCMSourceRetriever.retrieve(SCMSourceRetriever.java:80)
           at org.jenkinsci.plugins.workflow.libs.LibraryAdder.retrieve(LibraryAdder.java:150)
           at org.jenkinsci.plugins.workflow.libs.LibraryAdder.add(LibraryAdder.java:131)
           at org.jenkinsci.plugins.workflow.libs.LibraryDecorator$1.call(LibraryDecorator.java:114)
           at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:1065)
           at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:603)
           at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:581)
           at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:558)
           at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:298)
           at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:268)
           at groovy.lang.GroovyShell.parseClass(GroovyShell.java:688)
           at groovy.lang.GroovyShell.parse(GroovyShell.java:700)
           at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.doParse(CpsGroovyShell.java:129)
           at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.reparse(CpsGroovyShell.java:123)
           at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.parseScript(CpsFlowExecution.java:516)
           at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.start(CpsFlowExecution.java:479)
           at org.jenkinsci.plugins.workflow.job.WorkflowRun.run(WorkflowRun.java:252)
           at hudson.model.ResourceController.execute(ResourceController.java:97)
           at hudson.model.Executor.run(Executor.java:405)
          

           

          Magnus Bäck added a comment - - edited FWIW one of our users just experienced a very similar error; just a different path and a for a fetch operation rather than ls-remote. Running Jenkins 2.60.3 with 2.5.0 of the git client plugin. No NFS shares are involved in our case, just plain ext4 partitions mounted into the Docker container where Jenkins runs. git fetch --tags --progress origin +refs/heads/:refs/remotes/origin/ hudson.plugins.git.GitException: Command "git fetch --tags --progress origin +refs/heads/:refs/remotes/origin/" returned status code 128: stdout: stderr: fatal: cannot exec '/srv/jenkins/caches/git-a67f10a9b25be4c33f1701c0caff217e@tmp/ssh4168691036775888323.sh': Text file busy fatal: unable to fork at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.launchCommandIn(CliGitAPIImpl.java:1924) at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.launchCommandWithCredentials(CliGitAPIImpl.java:1643) at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.access$300(CliGitAPIImpl.java:71) at org.jenkinsci.plugins.gitclient.CliGitAPIImpl$1.execute(CliGitAPIImpl.java:352) at jenkins.plugins.git.AbstractGitSCMSource.doRetrieve(AbstractGitSCMSource.java:344) at jenkins.plugins.git.AbstractGitSCMSource.retrieve(AbstractGitSCMSource.java:524) at jenkins.scm.api.SCMSource.fetch(SCMSource.java:598) at org.jenkinsci.plugins.workflow.libs.SCMSourceRetriever.retrieve(SCMSourceRetriever.java:80) at org.jenkinsci.plugins.workflow.libs.LibraryAdder.retrieve(LibraryAdder.java:150) at org.jenkinsci.plugins.workflow.libs.LibraryAdder.add(LibraryAdder.java:131) at org.jenkinsci.plugins.workflow.libs.LibraryDecorator$1.call(LibraryDecorator.java:114) at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:1065) at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:603) at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:581) at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:558) at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:298) at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:268) at groovy.lang.GroovyShell.parseClass(GroovyShell.java:688) at groovy.lang.GroovyShell.parse(GroovyShell.java:700) at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.doParse(CpsGroovyShell.java:129) at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.reparse(CpsGroovyShell.java:123) at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.parseScript(CpsFlowExecution.java:516) at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.start(CpsFlowExecution.java:479) at org.jenkinsci.plugins.workflow.job.WorkflowRun.run(WorkflowRun.java:252) at hudson.model.ResourceController.execute(ResourceController.java:97) at hudson.model.Executor.run(Executor.java:405)  

          Mark Waite added a comment -

          magnusbaeck thanks for the report. I suspect the case you're seeing is due to multiple threads attempting to scan for repository changes on a multi-branch pipeline. Can you confirm the caches/git-xxx directory is pointing to a remote repository which is used by one or more multi-branch pipeline jobs?

          I don't have a fix for it, or even a workaround, since that message would usually mean that one thread is attempting to replace content in the temporary file which holds the credentials while another thread has called command line git with environment variables which will cause it to use that file as the credentials information source.

          It is also possible that command line git has been called after Java wrote the file but before Java closed the file. That would surprise me very much, since that file is written from within a try with resources block which should close the file on exit from the block.

          Mark Waite added a comment - magnusbaeck thanks for the report. I suspect the case you're seeing is due to multiple threads attempting to scan for repository changes on a multi-branch pipeline. Can you confirm the caches/git-xxx directory is pointing to a remote repository which is used by one or more multi-branch pipeline jobs? I don't have a fix for it, or even a workaround, since that message would usually mean that one thread is attempting to replace content in the temporary file which holds the credentials while another thread has called command line git with environment variables which will cause it to use that file as the credentials information source. It is also possible that command line git has been called after Java wrote the file but before Java closed the file. That would surprise me very much, since that file is written from within a try with resources block which should close the file on exit from the block.

          Magnus Bäck added a comment -

          Can you confirm the caches/git-xxx directory is pointing to a remote repository which is used by one or more multi-branch pipeline jobs?

          It's the git used for a shared pipeline library, which indeed is used in concurrently running pipeline jobs but each pipeline is single-branch.

          Magnus Bäck added a comment - Can you confirm the  caches/git-xxx  directory is pointing to a remote repository which is used by one or more multi-branch pipeline jobs? It's the git used for a shared pipeline library, which indeed is used in concurrently running pipeline jobs but each pipeline is single-branch.

          Mark Waite added a comment -

          magnusbaeck thanks for the confirmation.  Access to that cache is controlled by a lock so that there should only be one git process accessing that cache at a time.  If multiple processes are writing that cache at the same time it is unexpected.

          Mark Waite added a comment - magnusbaeck thanks for the confirmation.  Access to that cache is controlled by a lock so that there should only be one git process accessing that cache at a time.  If multiple processes are writing that cache at the same time it is unexpected.

          pixman20 added a comment -

          markewaite, I am having the same issue as magnusbaeck . We have a few hundred multi-branch pipeline jobs (created by the Bitbucket Branch Source Plugin) that all refer to a shared library. They all run during the night so it's easily possible that multiple jobs are trying to pull the shared library at the same time. It's worth noting that I am now using a git reference repository to speed up cloning, but I may have seen this issue prior to adding the reference repository as well. In theory the reference repo is irrelevant anyway since it's failing on /tmp/ssh....
          My stack trace is slightly different than the above description, so I'm pasting it in here in case it helps:

          hudson.plugins.git.GitException: Command "git ls-remote -h -t ssh://git@somegit:somport/someproject/somerepo.git" returned status code 128:
          stdout: 
          stderr: fatal: cannot exec '/tmp/ssh1395686403629394139.sh': Text file busy
          fatal: unable to fork
          
          	at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.launchCommandIn(CliGitAPIImpl.java:1990)
          	at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.launchCommandWithCredentials(CliGitAPIImpl.java:1709)
          	at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.launchCommandWithCredentials(CliGitAPIImpl.java:1620)
          	at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.launchCommandWithCredentials(CliGitAPIImpl.java:1611)
          	at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.getRemoteReferences(CliGitAPIImpl.java:2825)
          	at jenkins.plugins.git.AbstractGitSCMSource.retrieve(AbstractGitSCMSource.java:708)
          	at jenkins.scm.api.SCMSource.fetch(SCMSource.java:598)
          	at org.jenkinsci.plugins.workflow.libs.SCMSourceRetriever.retrieve(SCMSourceRetriever.java:80)
          	at org.jenkinsci.plugins.workflow.libs.LibraryAdder.retrieve(LibraryAdder.java:153)
          	at org.jenkinsci.plugins.workflow.libs.LibraryStep$Execution.run(LibraryStep.java:205)
          	at org.jenkinsci.plugins.workflow.libs.LibraryStep$Execution.run(LibraryStep.java:154)
          	at org.jenkinsci.plugins.workflow.steps.AbstractSynchronousNonBlockingStepExecution$1$1.call(AbstractSynchronousNonBlockingStepExecution.java:47)
          	at hudson.security.ACL.impersonate(ACL.java:274)
          	at org.jenkinsci.plugins.workflow.steps.AbstractSynchronousNonBlockingStepExecution$1.run(AbstractSynchronousNonBlockingStepExecution.java:44)
          	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
          	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
          	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
          	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
          	at java.lang.Thread.run(Thread.java:745)
          

          pixman20 added a comment - markewaite , I am having the same issue as magnusbaeck . We have a few hundred multi-branch pipeline jobs (created by the Bitbucket Branch Source Plugin) that all refer to a shared library. They all run during the night so it's easily possible that multiple jobs are trying to pull the shared library at the same time. It's worth noting that I am now using a git reference repository to speed up cloning, but I may have seen this issue prior to adding the reference repository as well. In theory the reference repo is irrelevant anyway since it's failing on /tmp/ssh.... My stack trace is slightly different than the above description, so I'm pasting it in here in case it helps: hudson.plugins.git.GitException: Command "git ls-remote -h -t ssh: //git@somegit:somport/someproject/somerepo.git" returned status code 128: stdout: stderr: fatal: cannot exec '/tmp/ssh1395686403629394139.sh' : Text file busy fatal: unable to fork at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.launchCommandIn(CliGitAPIImpl.java:1990) at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.launchCommandWithCredentials(CliGitAPIImpl.java:1709) at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.launchCommandWithCredentials(CliGitAPIImpl.java:1620) at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.launchCommandWithCredentials(CliGitAPIImpl.java:1611) at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.getRemoteReferences(CliGitAPIImpl.java:2825) at jenkins.plugins.git.AbstractGitSCMSource.retrieve(AbstractGitSCMSource.java:708) at jenkins.scm.api.SCMSource.fetch(SCMSource.java:598) at org.jenkinsci.plugins.workflow.libs.SCMSourceRetriever.retrieve(SCMSourceRetriever.java:80) at org.jenkinsci.plugins.workflow.libs.LibraryAdder.retrieve(LibraryAdder.java:153) at org.jenkinsci.plugins.workflow.libs.LibraryStep$Execution.run(LibraryStep.java:205) at org.jenkinsci.plugins.workflow.libs.LibraryStep$Execution.run(LibraryStep.java:154) at org.jenkinsci.plugins.workflow.steps.AbstractSynchronousNonBlockingStepExecution$1$1.call(AbstractSynchronousNonBlockingStepExecution.java:47) at hudson.security.ACL.impersonate(ACL.java:274) at org.jenkinsci.plugins.workflow.steps.AbstractSynchronousNonBlockingStepExecution$1.run(AbstractSynchronousNonBlockingStepExecution.java:44) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang. Thread .run( Thread .java:745)

            Unassigned Unassigned
            mbmop Mostyn Bramley-Moore
            Votes:
            8 Vote for this issue
            Watchers:
            27 Start watching this issue

              Created:
              Updated:
              Resolved: