{"record":{"id":"146ce6d506d81e8d","repo":"golang/go","slug":"command-cannot-be-run-in-background","errorCode":null,"errorMessage":"command cannot be run in background","messagePattern":"command cannot be run in background","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cmd/internal/script/engine.go","lineNumber":555,"sourceCode":"\t\tif err != nil {\n\t\t\treturn false, fmt.Errorf(\"evaluating condition %q: %w\", cond.tag, err)\n\t\t}\n\t\tif active != cond.want {\n\t\t\treturn false, nil\n\t\t}\n\t}\n\n\treturn true, nil\n}\n\nfunc (e *Engine) runCommand(s *State, cmd *command, impl Cmd) error {\n\tif impl == nil {\n\t\treturn cmdError(cmd, errors.New(\"unknown command\"))\n\t}\n\n\tasync := impl.Usage().Async\n\tif cmd.background && !async {\n\t\treturn cmdError(cmd, errors.New(\"command cannot be run in background\"))\n\t}\n\n\twait, runErr := impl.Run(s, cmd.args...)\n\tif wait == nil {\n\t\tif async && runErr == nil {\n\t\t\treturn cmdError(cmd, errors.New(\"internal error: async command returned a nil WaitFunc\"))\n\t\t}\n\t\treturn checkStatus(cmd, runErr)\n\t}\n\tif runErr != nil {\n\t\treturn cmdError(cmd, errors.New(\"internal error: command returned both an error and a WaitFunc\"))\n\t}\n\n\tif cmd.background {\n\t\ts.background = append(s.background, backgroundCmd{\n\t\t\tcommand: cmd,\n\t\t\twait:    wait,\n\t\t})","sourceCodeStart":537,"sourceCodeEnd":573,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/cmd/internal/script/engine.go#L537-L573","documentation":"Returned by Engine.runCommand when the parsed line ends with a background marker '&' (cmd.background == true) but the resolved command's Usage declares it as non-async. Only commands that opt in via CmdUsage{Async: true} may be backgrounded; attempting to background a synchronous command (like cd, mkdir, setenv) is rejected.","triggerScenarios":"A script line appending '&' to a non-async command, e.g. `cd dir &`, `mkdir x &`, `setenv K v &`. The parser sets cmd.background; runCommand reads impl.Usage().Async and, finding it false, returns the error.","commonSituations":"Script-test author assumes all commands support backgrounding (only long-running ones like exec do). Trailing '&' left from converting a shell snippet into a script test.","solutions":["Remove the trailing '&' from the command — it does not support background execution.","If you truly need concurrency, use a command declared Async (e.g. an exec-like command) instead.","Check impl.Usage().Async to learn which commands may be backgrounded in your engine."],"exampleFix":"// before\ncd subdir &\n# -> command cannot be run in background\n\n// after\ncd subdir","handlingStrategy":"validation","validationCode":"// Check whether a command may be backgrounded before writing the '&'.\nfunc canBackground(name string, cmds map[string]script.Cmd) bool {\n    c, ok := cmds[name]\n    if !ok { return false }\n    return c.Usage().Async\n}","typeGuard":"func isCantBackground(err error) bool {\n    var ce *script.CommandError\n    return errors.As(err, &ce) && ce.Err != nil && ce.Err.Error() == \"command cannot be run in background\"\n}","tryCatchPattern":"// Remove trailing '&' from non-async commands.","preventionTips":["Only append '&' to commands declared Async.","Consult Usage().Async to learn which commands background.","Prefer foreground for filesystem/state commands."],"tags":["script","engine","background","async","test-framework"],"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}