Skip to content

Commit 1a6b428

Browse files
committed
fix(agent/agentscripts): show informative error for ErrWaitDelay
1 parent 51aa32c commit 1a6b428

File tree

2 files changed

+19
-2
lines changed

2 files changed

+19
-2
lines changed

agent/agent.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -743,7 +743,7 @@ func (a *agent) run(ctx context.Context) error {
743743
return script.RunOnStart
744744
})
745745
if err != nil {
746-
a.logger.Warn(ctx, "startup script failed", slog.Error(err))
746+
a.logger.Warn(ctx, "startup script(s) failed", slog.Error(err))
747747
if errors.Is(err, agentscripts.ErrTimeout) {
748748
a.setLifecycle(ctx, codersdk.WorkspaceAgentLifecycleStartTimeout)
749749
} else {
@@ -1465,6 +1465,7 @@ func (a *agent) Close() error {
14651465
return script.RunOnStop
14661466
})
14671467
if err != nil {
1468+
a.logger.Warn(ctx, "shutdown script(s) failed", slog.Error(err))
14681469
if errors.Is(err, agentscripts.ErrTimeout) {
14691470
lifecycleState = codersdk.WorkspaceAgentLifecycleShutdownTimeout
14701471
} else {

agent/agentscripts/agentscripts.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ import (
2727
var (
2828
// ErrTimeout is returned when a script times out.
2929
ErrTimeout = xerrors.New("script timed out")
30+
// ErrTimeout is returned when a script times out.
31+
ErrOutputPipesOpen = xerrors.New("script exited without closing output pipes")
3032

3133
parser = cron.NewParser(cron.Second | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.DowOptional)
3234
)
@@ -248,7 +250,21 @@ func (r *Runner) run(ctx context.Context, script codersdk.WorkspaceAgentScript)
248250
err = cmdCtx.Err()
249251
case err = <-cmdDone:
250252
}
251-
if errors.Is(err, context.DeadlineExceeded) {
253+
switch {
254+
case errors.Is(err, exec.ErrWaitDelay):
255+
err = ErrOutputPipesOpen
256+
message := fmt.Sprintf("script exited successfully, but output pipes were not closed after %s", cmd.WaitDelay)
257+
details := fmt.Sprint(
258+
"This usually means a child process was started with references to stdout or stderr. As a result, this " +
259+
"process may now have been terminated. Consider using a separate \"coder_script\" for the service, " +
260+
"see https://coder.com/docs/v2/latest/templates/troubleshooting#startup-script-issues for more information.",
261+
)
262+
// Inform the user by propagating the message via log writers.
263+
_, _ = fmt.Fprintf(cmd.Stderr, "WARNING: %s. %s\n", message, details)
264+
// Also log to agent logs for ease of debugging.
265+
r.Logger.Warn(ctx, message, slog.F("details", details), slog.Error(err))
266+
267+
case errors.Is(err, context.DeadlineExceeded):
252268
err = ErrTimeout
253269
}
254270
return err

0 commit comments

Comments
 (0)