tailscale/tailscale · error

failed to send %d logs

Error message

failed to send %d logs

What it means

Raised by Logger.flush when some pending audit logs could not be delivered to the control plane transport. The unsent entries were persisted back to the store for a later retry; the count reports how many remain.

Source

Thrown at ipn/auditlog/auditlog.go:262

	}
	if len(pending) == 0 {
		return nil
	}
	if t == nil {
		return errors.New("no transport")
	}

	complete, unsent := al.sendToTransport(ctx, pending, t)
	al.markTransactionsDone(complete)

	al.mu.Lock()
	defer al.mu.Unlock()
	if err = al.appendToStoreLocked(unsent); err != nil {
		al.logf("[unexpected] failed to persist logs: %v", err)
	}

	if len(unsent) != 0 {
		return fmt.Errorf("failed to send %d logs", len(unsent))
	}

	if len(complete) != 0 {
		al.logf("complete %d audit log transactions", len(complete))
	}
	return nil
}

// sendToTransport sends all pending logs to the control plane. Returns a pair of slices
// containing the logs that were successfully sent (or failed permanently) and those that were not.
//
// This may require multiple round trips to the control plane and can be a long running transaction.
func (al *Logger) sendToTransport(ctx context.Context, pending []*transaction, t Transport) (complete []*transaction, unsent []*transaction) {
	for i, txn := range pending {
		req := tailcfg.AuditLogRequest{
			Action:    tailcfg.ClientAuditAction(txn.Action),
			Details:   txn.Details,
			Timestamp: txn.TimeStamp,

View on GitHub (pinned to 6e0912f979)

Solutions

  1. Wait for the retry timer; delivery resumes when control is reachable.
  2. Check control-plane connectivity if the count does not decrease.
Defensive patterns

Strategy: retry

When it happens

Trigger: Thrown at ipn/auditlog/auditlog.go:262 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of tailscale/tailscale@6e0912f979 (2026-08-18). Data as JSON: /api/errors/6bb85e313e15ea1f. Report an issue: GitHub.