vxcontrol/pentagi · warning

failed to put terminal log (write file cmd)

Error message

failed to put terminal log (write file cmd): %w

What it means

After writeFileToContainer succeeds, WriteFile emits an ANSI-styled 'File successfully saved' entry to the flow's terminal log via tlp.PutMsg (TermlogTypeStdin). If that logging write fails — DB down, context canceled, terminal-log storage error — the whole operation is reported as failed with this wrapper even though the file was already written to the container.

Solutions

  1. Check database connectivity and logs (PostgreSQL up, pool not exhausted) — this is a logging-side failure, not a Docker one
  2. Retry the WriteFile call; the file write is idempotent (same content overwrites)
  3. Decouple logging from the result path: log the PutMsg error (non-fatal) instead of failing a write that already succeeded
  4. Verify ctx deadlines upstream aren't expiring between the Docker put and the log insert

Example fix

// before
_, err := t.tlp.PutMsg(ctx, database.TermlogTypeStdin, styledMsg, t.containerID, t.taskID, t.subtaskID)
if err != nil {
    return "", fmt.Errorf("failed to put terminal log (write file cmd): %w", err)
}
// after
if _, err := t.tlp.PutMsg(ctx, database.TermlogTypeStdin, styledMsg, t.containerID, t.taskID, t.subtaskID); err != nil {
    logger.WarnContext(ctx, "termlog write failed for file save", "path", path, "err", err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-call: ensure the termlog store is reachable
if err := db.PingContext(ctx); err != nil {
    return fmt.Errorf("terminal log store unavailable: %w", err)
}

Try / catch

if _, err := tlp.PutMsg(ctx, database.TermlogTypeStdin, styledMsg, containerID, taskID, subtaskID); err != nil {
    logger.WarnContext(ctx, "termlog write failed; file already saved", "path", path, "err", err)
    // do not fail the whole write for a logging error
}

Prevention

When it happens

Trigger: The file content was successfully put into the container, but the subsequent PutMsg to the termlog store returned an error: PostgreSQL unreachable/rolled back, ctx deadline exceeded during the log insert, or the terminal-log record for the container/task/subtask is in a bad state.

Common situations: Database failover or connection-pool exhaustion during heavy flow activity; request context canceled by an upstream HTTP/GraphQL timeout right after the Docker write completed; migration/schema drift on the termlog table.

Related errors


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

Appendix: source

Thrown at backend/pkg/tools/terminal.go:441

	return buffer.String(), nil
}

func (t *terminal) WriteFile(ctx context.Context, flowID int64, content string, path string) (string, error) {
	if path == "" {
		return "", fmt.Errorf("path is required and cannot be empty")
	}

	if err := t.writeFileToContainer(ctx, flowID, path, content); err != nil {
		return "", err
	}

	// Format success message with styling
	successMsg := fmt.Sprintf("File successfully saved to %s", path)
	styledMsg := fmt.Sprintf("%s%s%s%s", ansiColorSystemMsg, successMsg, ansiColorReset, ansiLineTerminator)
	_, err := t.tlp.PutMsg(ctx, database.TermlogTypeStdin, styledMsg, t.containerID, t.taskID, t.subtaskID)
	if err != nil {
		return "", fmt.Errorf("failed to put terminal log (write file cmd): %w", err)
	}

	return fmt.Sprintf("Successfully wrote %d bytes to %s", len(content), path), nil
}

// writeFileToContainer copies content into the flow's container at path,
// overwriting it. It performs no terminal-log writes; WriteFile and EditFile
// each log their own, differently-worded, success message.
func (t *terminal) writeFileToContainer(ctx context.Context, flowID int64, path, content string) error {
	containerName := PrimaryTerminalName(t.tenantPrefix, flowID)

	isRunning, err := t.dockerClient.IsContainerRunning(ctx, t.containerLID)
	if err != nil {
		return fmt.Errorf("container runtime check failed: %w", err)
	}
	if !isRunning {
		return fmt.Errorf("target container is not operational")
	}

View on GitHub (pinned to ea665308ba)