0X8032000D

FWP_E_NO_TXN_IN_PROGRESS Fix: It's Always the Transaction Scope

Database Errors Intermediate 👁 0 views 📅 May 28, 2026

You're calling a transaction-bound WebPI function outside an explicit transaction. The fix is wrapping the call in a transaction scope or switching to the non-transactional version of the function.

I've been debugging this same error for years, and it always comes down to the same thing — you're calling a transaction-bound function without an active transaction. Don't waste time chasing firewall rules or service restarts. Let's fix it.

The Fix

The culprit here is almost always a call to FwpmFilterAdd0, FwpmCalloutRegister, or FwpmSubLayerAdd0 outside a transaction. All WFP changes that modify state must be wrapped in an explicit transaction using the FwpmTransactionBegin0, FwpmTransactionCommit0, and FwpmTransactionAbort0 functions.

Here's the pattern you need:

// Open engine handle
HANDLE engineHandle;
FWPM_SESSION session = {0};
session.flags = FWPM_SESSION_FLAG_DYNAMIC;

FwpmEngineOpen(NULL, RPC_C_AUTHN_WINNT, NULL, &session, &engineHandle);

// Begin the transaction
FWPM_FILTER filter = {0};
// ... set up your filter ...

DWORD result = FwpmTransactionBegin0(engineHandle, 0);
if (result != ERROR_SUCCESS) {
    printf("Transaction begin failed: %lx", result);
    FwpmEngineClose(engineHandle);
    return 1;
}

// Call the function that was throwing 0x8032000D
result = FwpmFilterAdd0(engineHandle, &filter, NULL, NULL);
if (result != ERROR_SUCCESS) {
    FwpmTransactionAbort0(engineHandle);
    printf("Filter add failed: %lx", result);
    FwpmEngineClose(engineHandle);
    return 1;
}

// Commit the changes
result = FwpmTransactionCommit0(engineHandle);
if (result != ERROR_SUCCESS) {
    FwpmTransactionAbort0(engineHandle);
    printf("Commit failed: %lx", result);
    FwpmEngineClose(engineHandle);
    return 1;
}

FwpmEngineClose(engineHandle);

If you're adding multiple objects (say, a sublayer and then five filters under it), wrap all those calls in a single transaction. WFP transactions are server-side — they hold a lock on the Base Filtering Engine (BFE) database. Commit fast, or users will see lag in network behavior.

Why This Error Happens

WFP uses explicit transactions by design. It's not like SQL where you can auto-commit. Microsoft decided that network filtering changes are too risky to apply without a clear start and end boundary. When you call a function like FwpmFilterAdd0 without first calling FwpmTransactionBegin0, BFE returns 0x8032000D — literally "no transaction in progress."

The older Fwps functions (the callout API) don't need transactions — they hook into the network stack directly. But any Fwpm function that changes the persistent firewall configuration does. Check the MSDN docs: if a function is in the Fwpm* namespace and it modifies state, it needs a transaction.

Less Common Variations

There are a few edge cases where this error sneaks in differently:

  1. Transaction timeout. If you open a transaction but take longer than the default timeout (60 seconds on most systems), BFE aborts it. Then your next call to FwpmFilterAdd0 — even if you think the transaction is still open — throws 0x8032000D. Check your loop or user input handling. Keep transactions under 30 seconds.
  2. Nested transactions. WFP doesn't support nested transactions. Calling FwpmTransactionBegin0 twice without a commit or abort in between will fail. Your second transaction attempt returns 0x8032000D because the first one is still active. Always check the return value of FwpmTransactionBegin0 — it's not always ERROR_SUCCESS.
  3. Dynamic sessions with flags. If you open the engine with FWPM_SESSION_FLAG_DYNAMIC, changes are temporary and not saved to the registry. But they still need a transaction. Some devs assume dynamic mode is transaction-free — it's not.
  4. Using the wrong API version. If you're calling FwpmFilterAdd0 but your code was written for the older FwpmFilterAdd (no version number), you might be passing mismatched structures. That won't give you this exact error, but it's a common misdiagnosis.

Prevention

Build a helper function or wrapper that handles the transaction lifecycle. Something like this:

DWORD WfpSafeModify(HANDLE engine, std::function<DWORD()> modifyFunc) {
    DWORD result = FwpmTransactionBegin0(engine, 0);
    if (result != ERROR_SUCCESS) return result;

    result = modifyFunc();
    if (result != ERROR_SUCCESS) {
        FwpmTransactionAbort0(engine);
        return result;
    }

    result = FwpmTransactionCommit0(engine);
    if (result != ERROR_SUCCESS) {
        FwpmTransactionAbort0(engine);
    }
    return result;
}

Also, log the return value of every WFP function call during development. Not just the one that fails. A failed FwpmTransactionBegin0 can look the same as a failed filter add if you're not checking each step.

One last thing: if you're writing a service that modifies WFP rules dynamically (like a VPN client), make sure your transaction code runs on the same thread that opened the engine handle. WFP sessions are thread-bound. Cross-thread calls without proper marshaling will give you this error or worse — a crash.

Was this solution helpful?