netbirdio/netbird · info

delete state: %w

Error message

delete state: %w

What it means

Final step of Manager.Close, executed only when every other cleanup succeeded: stateManager.DeleteState removes the persisted 'iptables_state' ShutdownState entry. Its failure means the state file/directory could not be written or removed (filesystem error). The consequence is benign by design - the stale state makes the next startup re-run ShutdownState.Cleanup, which tolerates already-absent rules and ipsets.

Source

Thrown at client/firewall/iptables/manager_linux.go:368

	}

	if err := m.aclMgr.Reset(); err != nil {
		merr = multierror.Append(merr, fmt.Errorf("reset acl manager: %w", err))
	}
	if err := m.router.Reset(); err != nil {
		merr = multierror.Append(merr, fmt.Errorf("reset router: %w", err))
	}

	// Appending to merr intentionally blocks DeleteState below so ShutdownState
	// stays persisted and the crash-recovery path retries firewalld cleanup.
	if err := firewalld.UntrustInterface(m.wgIface.Name()); err != nil {
		merr = multierror.Append(merr, err)
	}

	// attempt to delete state only if all other operations succeeded
	if merr == nil {
		if err := stateManager.DeleteState(&ShutdownState{}); err != nil {
			merr = multierror.Append(merr, fmt.Errorf("delete state: %w", err))
		}
	}

	return nberrors.FormatErrorOrNil(merr)
}

// AllowNetbird allows netbird interface traffic.
// This is called when USPFilter wraps the native firewall, adding blanket accept
// rules so that packet filtering is handled in userspace instead of by netfilter.
func (m *Manager) AllowNetbird() error {
	var merr *multierror.Error
	if _, err := m.AddPeerFiltering(nil, net.IP{0, 0, 0, 0}, firewall.ProtocolALL, nil, nil, firewall.ActionAccept, ""); err != nil {
		merr = multierror.Append(merr, fmt.Errorf("allow netbird v4 interface traffic: %w", err))
	}
	if m.hasIPv6() {
		if _, err := m.AddPeerFiltering(nil, net.IPv6zero, firewall.ProtocolALL, nil, nil, firewall.ActionAccept, ""); err != nil {
			merr = multierror.Append(merr, fmt.Errorf("allow netbird v6 interface traffic: %w", err))
		}

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. No immediate action needed: the next start re-runs cleanup idempotently
  2. Check the agent state directory permissions and free space
  3. Delete the stale iptables_state entry/file manually if startup noise is unacceptable
Defensive patterns

Strategy: retry

Validate before calling

// ensure the state directory is writable before shutdown
dir := statemanager.GetDefaultDirectory() // or your configured state path
if info, err := os.Stat(dir); err != nil || !info.IsDir() {
    log.Warnf("state dir unhealthy, shutdown state may persist: %v", err)
}

Try / catch

if err := mgr.Close(stateManager); err != nil {
    if strings.Contains(err.Error(), "delete state") {
        // cleanup itself succeeded; only the state-file removal failed. Benign:
        // next start re-runs an idempotent cleanup.
        log.Debugf("stale shutdown state kept: %v", err)
        return nil
    }
    return err
}

Prevention

When it happens

Trigger: Close reaching DeleteState and the state manager failing to persist the removal - read-only state directory, disk full, permission change, or the state file deleted underneath the manager.

Common situations: State directory on a full or read-only filesystem; permissions changed between start and stop; containerized agent with an ephemeral or overlaid state path.

Related errors


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/8b348ea6b637dc0e. Report an issue: GitHub.