This error means the server received your SOAP request but could not route it to any operation in its service contract. The dispatcher could not match the incoming Action to a known operation.
The message with Action '' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher.
You see this frequently in WCF services, SAP integrations that route through .NET endpoints, and any SOAP service that uses WS-Addressing or action-based dispatching.
How SOAPAction routing works
SOAP services use the Action value to determine which operation to invoke. The mechanism differs between SOAP 1.1 and SOAP 1.2.
SOAP 1.1: SOAPAction HTTP header
In SOAP 1.1, the action is a separate HTTP header. It must exactly match what the server expects.
POST /service.svc HTTP/1.1
Host: example.com
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://tempuri.org/IUserService/GetUser"
Key details:
- The value is typically enclosed in double quotes
- It is case-sensitive
- An empty
SOAPAction: ""is valid SOAP but means "no action specified" — which is what triggers theAction ''error - Omitting the header entirely may also result in an empty action
SOAP 1.2: action parameter in Content-Type
In SOAP 1.2, the action moves into the Content-Type header as a parameter.
POST /service.svc HTTP/1.1
Host: example.com
Content-Type: application/soap+xml; charset=utf-8; action="http://tempuri.org/IUserService/GetUser"
If you send a SOAP 1.2 request but use a separate SOAPAction header instead of the action parameter in Content-Type, the server may ignore it — resulting in the same ContractFilter mismatch.
Step 1: Find the correct action in the WSDL
The WSDL defines the action for each operation. Here is how to locate it.
<wsdl:binding name="UserServiceSoap" type="tns:IUserService">
<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="GetUser">
<soap:operation
soapAction="http://tempuri.org/IUserService/GetUser"
style="document" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
The soapAction attribute on <soap:operation> is the exact string you must send. Copy it character for character — including the path, casing, and trailing slash if present.
For WCF services, the action often follows the pattern:
http://tempuri.org/IServiceName/OperationName
If the service uses a custom namespace, it will be reflected in the WSDL.
Step 2: Debug with curl
Send a minimal request and inspect the response.
# SOAP 1.1 — SOAPAction as a separate header
curl -v \
-H "Content-Type: text/xml; charset=utf-8" \
-H 'SOAPAction: "http://tempuri.org/IUserService/GetUser"' \
-d '<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<GetUser xmlns="http://tempuri.org/">
<userId>1</userId>
</GetUser>
</soap:Body>
</soap:Envelope>' \
https://example.com/service.svc
# SOAP 1.2 — action inside Content-Type
curl -v \
-H "Content-Type: application/soap+xml; charset=utf-8; action=\"http://tempuri.org/IUserService/GetUser\"" \
-d '<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Body>
<GetUser xmlns="http://tempuri.org/">
<userId>1</userId>
</GetUser>
</soap12:Body>
</soap12:Envelope>' \
https://example.com/service.svc
If the SOAP 1.1 request with the correct SOAPAction returns a valid response, your issue was a missing or incorrect action header. If it still fails, check whether the service only accepts SOAP 1.2.
Step 3: Fix client configuration
WCF client — web.config
The most common WCF cause is a binding that does not include the action, or an endpoint that points to the wrong service contract.
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="UserServiceSoap" />
</basicHttpBinding>
</bindings>
<client>
<endpoint
address="https://example.com/service.svc"
binding="basicHttpBinding"
bindingConfiguration="UserServiceSoap"
contract="UserService.IUserService"
name="UserServiceSoap" />
</client>
</system.serviceModel>
Verify that:
- The
contractattribute matches the service interface exactly - The
addresspoints to the correct endpoint (not the WSDL URL) - The binding type matches the SOAP version the server expects
- If using
wsHttpBinding, security settings (message vs transport) match the server
WCF — adding a custom action programmatically
If the generated client does not send the action correctly, you can override it:
using (var scope = new OperationContextScope(client.InnerChannel))
{
var action = new HttpRequestMessageProperty();
action.Headers["SOAPAction"] = "\"http://tempuri.org/IUserService/GetUser\"";
OperationContext.Current.OutgoingMessageProperties[
HttpRequestMessageProperty.Name] = action;
var result = client.GetUser(userId);
}
Common pitfalls
- Trailing slashes:
http://tempuri.org/IUserService/GetUserandhttp://tempuri.org/IUserService/GetUser/are different actions - Namespace mismatch: The action URI must match the namespace defined in the service contract, not just the endpoint URL
- Empty action from proxy tools: Some HTTP proxy tools strip or modify the SOAPAction header — always verify with a raw curl request
- Multiple endpoints: WCF services may expose multiple endpoints with different contracts. Make sure you are calling the correct one.
Why this keeps happening across teams
Every consumer that integrates directly with a SOAP service must independently discover:
- the correct action URI for each operation
- whether to use SOAP 1.1 or 1.2 action semantics
- the exact endpoint URL for the right binding
This is duplicated integration work that leads to the same debugging session across teams.
How SOAPless resolves this automatically
When you register a WSDL with SOAPless, the engine parses every operation and its corresponding soapAction value from the WSDL. When a downstream consumer calls the REST JSON endpoint, SOAPless automatically constructs the correct SOAP request with the right Action header — whether that is a SOAPAction HTTP header for SOAP 1.1 or an action parameter in Content-Type for SOAP 1.2.
No consumer ever needs to know what the SOAPAction string is. The WSDL is the single source of truth, and SOAPless reads it once so your team does not have to.