syncthing/syncthing · error

handling %v: %w

Error message

handling %v: %w

What it means

Wraps an error that occurred while processing (not decoding) an already-parsed BEP message, such as applying an index or dispatching a Request to a handler. The %v names the message context and %w the handler failure. It is produced by newHandleError at the dispatch point in the message loop (protocol.go:509), distinguishing downstream handler failures from wire-format errors.

Source

Thrown at lib/protocol/protocol.go:1119

		return nil, fmt.Errorf("decompressed message len %d is too large", size)
	}
	buf := BufferPool.Get(int(size))

	n, err := lz4.UncompressBlock(src[4:], buf)
	if err != nil {
		BufferPool.Put(buf)
		return nil, err
	}

	return buf[:n], nil
}

func newProtocolError(err error, msgContext string) error {
	return fmt.Errorf("protocol error on %v: %w", msgContext, err)
}

func newHandleError(err error, msgContext string) error {
	return fmt.Errorf("handling %v: %w", msgContext, err)
}

func messageContext(msg proto.Message) (string, error) {
	switch msg := msg.(type) {
	case *bep.ClusterConfig:
		return "cluster-config", nil
	case *bep.Index:
		return fmt.Sprintf("index for %v", msg.Folder), nil
	case *bep.IndexUpdate:
		return fmt.Sprintf("index-update for %v", msg.Folder), nil
	case *bep.Request:
		return fmt.Sprintf(`request for "%v" in %v`, msg.Name, msg.Folder), nil
	case *bep.Response:
		return "response", nil
	case *bep.DownloadProgress:
		return fmt.Sprintf("download-progress for %v", msg.Folder), nil
	case *bep.Ping:
		return "ping", nil

View on GitHub (pinned to 058bcd7334)

Solutions

  1. Check which message context appears in the error text (e.g. 'index for X') and verify that folder is shared and configured on both devices
  2. Inspect the wrapped %w error — it names the real handler failure (disk, database, unknown folder)
  3. Sync folder configs across devices and restart the connection so a fresh ClusterConfig is exchanged
  4. If persistent, rescan or reset the folder index database on the affected device

Example fix

// before: handler error surfaces opaquely
case errors.As(err, &e):
    log.Printf("sync failed: %v", err)
// after: unwrap to distinguish handle vs protocol errors via error text
if strings.HasPrefix(err.Error(), "handling ") {
    log.Printf("handler failure on message: %v", errors.Unwrap(err))
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before exchanging indexes, confirm the folder is actually shared both ways
for _, folder := range myFolders {
    if !peerSharesFolder(peerID, folder.ID) {
        return fmt.Errorf("folder %s not shared with peer", folder.ID)
    }
}

Type guard

func isHandleError(err error) bool {
    return err != nil && strings.HasPrefix(err.Error(), "handling ")
}

Try / catch

if err := msgLoop(); err != nil {
    if isHandleError(err) {
        // inspect errors.Unwrap(err) for the real cause; may be per-folder and non-fatal
        l.Warnf("message handler failed: %v", errors.Unwrap(err))
    }
}

Prevention

When it happens

Trigger: The messageLoop dispatches a decoded message to its handler (index processing, request handling, cluster-config processing) and the handler returns a non-nil error; e.g. an index for an unknown folder or a request for a file that cannot be opened.

Common situations: Folder removed from config on one side while the other still sends index updates; disk full or file locked when serving a Request; database errors in the folder while applying an index; partial config propagation in a cluster.

Related errors


AI-assisted analysis of syncthing/syncthing@058bcd7334 (2026-08-15). Data as JSON: /api/errors/8b8391d078290d91. Report an issue: GitHub.