vxcontrol/pentagi · error

failed to put input for subtask %d: %w

Error message

failed to put input for subtask %d: %w

What it means

After passing the state guards, PutInput pushes the user input into the LLM agent message chain via Provider.PutInputToAgentChain. If that provider call fails, the error is wrapped as 'failed to put input for subtask %d'. The input never reached the chain, so the subtask stays Waiting and Run can later resume it.

Source

Thrown at backend/pkg/controller/subtask.go:271

	if err != nil {
		return fmt.Errorf("failed to set subtask %d result: %w", stw.subtaskCtx.SubtaskID, err)
	}

	return nil
}

func (stw *subtaskWorker) PutInput(ctx context.Context, input string) error {
	if stw.IsCompleted() {
		return fmt.Errorf("subtask has already completed")
	}

	if !stw.IsWaiting() {
		return fmt.Errorf("subtask is not waiting, run first")
	}

	err := stw.subtaskCtx.Provider.PutInputToAgentChain(ctx, stw.subtaskCtx.MsgChainID, input)
	if err != nil {
		return fmt.Errorf("failed to put input for subtask %d: %w", stw.subtaskCtx.SubtaskID, err)
	}

	_, err = stw.subtaskCtx.MsgLog.PutSubtaskMsg(
		ctx,
		database.MsglogTypeInput,
		stw.subtaskCtx.TaskID,
		stw.subtaskCtx.SubtaskID,
		"", // thinking is empty because this is input
		input,
	)
	if err != nil {
		return fmt.Errorf("failed to put input for subtask %d: %w", stw.subtaskCtx.SubtaskID, err)
	}

	stw.mx.Lock()
	defer stw.mx.Unlock()

	stw.waiting = false

View on GitHub (pinned to ea665308ba)

Solutions

  1. Inspect the wrapped provider error; if it's a DB error check connectivity/migrations first.
  2. Retry PutInput with backoff — the subtask remains Waiting so a retry is safe from the chain's perspective.
  3. Verify the MsgChainID still exists (flow not replaced/deleted); if the chain is gone, abandon this worker and create a new subtask.
  4. Reject empty input at the caller before invoking PutInput.

Example fix

// before
if err := worker.PutInput(ctx, input); err != nil {
	return err
}
// after
var err error
for i := 0; i < 3; i++ {
	if err = worker.PutInput(ctx, input); err == nil {
		break
	}
	time.Sleep(time.Duration(1<<i) * time.Second)
}
return err
Defensive patterns

Strategy: retry

Validate before calling

// basic sanity before pushing input into the chain
if strings.TrimSpace(input) == "" {
	return fmt.Errorf("input must not be empty")
}
if worker.GetMsgChainID() == 0 {
	return fmt.Errorf("subtask has no message chain")
}

Try / catch

if err := worker.PutInput(ctx, input); err != nil {
	if isContextErr(err) {
		time.Sleep(backoff)
		return worker.PutInput(ctx, input) // safe: subtask still Waiting
	}
	return err
}

Prevention

When it happens

Trigger: PutInputToAgentChain fails because the message-chain store is unavailable, the chain for MsgChainID was deleted (e.g. flow replacement), or the provider rejects the input (empty string, chain in an unexpected internal state).

Common situations: Postgres/vector-store outage during user input submission; concurrent flow restart deleting the msg chain while the user was typing an answer; provider implementation bug or mismatched MsgChainID after a DB restore.

Related errors


AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01). Data as JSON: /api/errors/bd507678841d3a56. Report an issue: GitHub.