https://pact.io logo
Join Slack
Powered by
# pact-net
  • g

    GitHub

    11/10/2025, 5:35 AM
    #554 chore: fix json schema url Pull request opened by JP-Ellis Schema Store seem to have changed the URL; and while the previous 'json' subdomain should redirect, it seems flakey and results in failures in CI. pact-foundation/pact-net
    • 1
    • 1
  • g

    GitHub

    11/10/2025, 5:55 AM
    1 new commit pushed to
    <https://github.com/pact-foundation/pact-net/tree/master|master>
    by JP-Ellis
    <https://github.com/pact-foundation/pact-net/commit/6c88659ee367f3fab7a269e876166d885cdc79d3|6c88659e>
    - chore: fix json schema url pact-foundation/pact-net
  • g

    GitHub

    12/28/2025, 10:49 PM
    #555 Suspicious matching async message payload int (35) -&gt; int (30) from the sample code Issue created by kieronwraywork Previous issues Have you searched the issue tracker to ensure this hasn't been discussed before? None found Version information: • OS: Windows x64 • PactNet Version: [MASTER] from this repo • .Net Version: 8.0 • Pact Broker Version (if applicable): NA Describe the bug There is an asynchronous event from the SAMPLES project in this repo, the body contents are matched even though the numbers are different in the content Steps To Reproduce Use this repo pact-net, samples project, change line 137 in the json (this is the contents\content payload for the Asynchronous/Messages type, change the "id" from 1 to any other number. Change the
    providertests
    code to generate OrderCreatedEvent with any number other than 1 Expected behavior Pact Verify test should fail with body content mismatch Log Output
    Copy code
    ated"}: pact_verifier::messages: actual message = AsynchronousMessage { id: None, key: None, description: "Asynchronous/Message Interaction", provider_states: [], contents: MessageContents { contents: Present(b"{\"id\":30}", Some(ContentType { main_type: "application", sub_type: "json", attributes: {}, suffix: None }), None), metadata: {"contentType": String("application/json")}, matching_rules: MatchingRules { rules: {} }, generators: Generators { categories: {} } }, comments: {}, pending: false, plugin_config: {}, interaction_markup: InteractionMarkup { markup: "", markup_type: "" }, transport: None }
    
    2025-12-28T21:57:19.815008Z DEBUG ThreadId(01) verify_interaction{interaction="an event indicating that an order has been created"}: pact_matching: comparing to expected message: AsynchronousMessage { id: None, key: None, description: "an event indicating that an order has been created", provider_states: [], contents: MessageContents { contents: Present(b"{\"id\":35}", Some(ContentType { main_type: "application", sub_type: "json", attributes: {}, suffix: None }), None), metadata: {}, matching_rules: MatchingRules { rules: {BODY: MatchingRuleCategory { name: BODY, rules: {DocPath { path_tokens: [Root, Field("id")], expr: "$.id" }: RuleList { rules: [Integer], rule_logic: And, cascaded: false }} }} }, generators: Generators { categories: {} } }, comments: {}, pending: false, plugin_config: {}, interaction_markup: InteractionMarkup { markup: "", markup_type: "" }, transport: None }
    
    2025-12-28T21:57:19.815059Z DEBUG ThreadId(01) verify_interaction{interaction="an event indicating that an order has been created"}: pact_matching: expected content type = 'application/json', actual content type = 'application/json'
    
    2025-12-28T21:57:19.815069Z DEBUG ThreadId(01) verify_interaction{interaction="an event indicating that an order has been created"}: pact_plugin_driver::catalogue_manager: Looking for a content matcher for application/json
    
    2025-12-28T21:57:19.815900Z DEBUG ThreadId(01) verify_interaction{interaction="an event indicating that an order has been created"}: pact_matching: No content matcher defined for content type 'application/json', using core matcher implementation
    
    2025-12-28T21:57:19.815909Z DEBUG ThreadId(01) verify_interaction{interaction="an event indicating that an order has been created"}: pact_matching: Using body matcher for content type 'application/json'
    
    2025-12-28T21:57:19.815917Z DEBUG ThreadId(01) verify_interaction{interaction="an event indicating that an order has been created"}: pact_matching::json: compare: Comparing path $
    
    2025-12-28T21:57:19.815919Z DEBUG ThreadId(01) verify_interaction{interaction="an event indicating that an order has been created"}: pact_matching::json: compare_maps: Comparing maps at $: {"id": Number(35)} -> {"id": Number(30)}
    
    2025-12-28T21:57:19.815944Z DEBUG ThreadId(01) verify_interaction{interaction="an event indicating that an order has been created"}: pact_matching::json: compare: Comparing path $.id
    
    2025-12-28T21:57:19.815949Z DEBUG ThreadId(01) verify_interaction{interaction="an event indicating that an order has been created"}: pact_matching::json: compare_values: Calling match_values for path $.id
    
    2025-12-28T21:57:19.815953Z DEBUG ThreadId(01) verify_interaction{interaction="an event indicating that an order has been created"}: pact_matching::json: JSON -> JSON: Comparing '35' (Integer) to '30' (Integer) using Integer -> Ok(())
    
    2025-12-28T21:57:19.815957Z DEBUG ThreadId(01) verify_interaction{interaction="an event indicating that an order has been created"}: pact_matching::json: compare_values: Comparing 'Number(35)' to 'Number(30)' at path '$.id' -> Ok(())
    
    2025-12-28T21:57:19.815975Z DEBUG ThreadId(01) verify_interaction{interaction="an event indicating that an order has been created"}: pact_matching: Matching message metadata
    
    2025-12-28T21:57:19.815977Z DEBUG ThreadId(01) verify_interaction{interaction="an event indicating that an order has been created"}: pact_matching: Matching message metadata. Expected '{"contentType": String("application/json")}', Actual '{"contentType": String("application/json")}'
    
    2025-12-28T21:57:19.815982Z DEBUG ThreadId(01) verify_interaction{interaction="an event indicating that an order has been created"}: pact_matching: Comparing metadata values for key 'contentType'
    
    2025-12-28T21:57:19.815989Z DEBUG ThreadId(01) verify_interaction{interaction="an event indicating that an order has been created"}: pact_matching: Comparing message context type '"application/json"' => '"application/json"'
    Additional context Suspicious text compare_values: Comparing 'Number(35)' to 'Number(30)' at path '$.id' -> Ok(())
    Fulfilment API-Orders API.json
    excerpt of contents
    Copy code
    {
      "contents": {
        "content": {
          "id": 35
        },
        "contentType": "application/json",
        "encoded": false
      },
      "description": "an event indicating that an order has been created",
      "matchingRules": {
        "body": {
          "$.id": {
            "combine": "AND",
            "matchers": [
              {
                "match": "integer"
              }
            ]
          }
        }
      },
      "pending": false,
      "type": "Asynchronous/Messages"
    }
    pact-foundation/pact-net
    • 1
    • 1
  • p

    Paul Williams

    03/02/2026, 8:38 AM
    @Paul Williams has left the channel
  • n

    Norbert Gulácsi

    03/25/2026, 12:17 PM
    @Norbert Gulácsi has left the channel
  • v

    Vaibhav Suryawanshi

    04/14/2026, 5:18 AM
    Need help, how the implementation is done at provider side in real time multiservice .net project?
    m
    • 2
    • 1
  • v

    Vaibhav Suryawanshi

    04/14/2026, 9:32 AM
    while provider verification, it spins up real app server, or we create a mock server instead of real one, in real time project?
  • m

    Matt (pactflow.io / pact-js / pact-go)

    04/14/2026, 10:15 AM
    You need to spin up your app server to test it. Message Pact is a little different, but can you please elaborate a bit further on the use case then we can advise more
  • g

    GitHub

    06/08/2026, 2:23 PM
    #550 RFC: Support for synchronous messaging Issue created by evoclint Do you intend to implement synchronous messaging? I can see in the roadmap it isn't yet supported for PactNet, if you intend to support it do you have a rough idea when this will be? pact-foundation/pact-net
    • 1
    • 1
  • g

    GitHub

    07/13/2026, 8:05 AM
    #545 PublishResult with / in the provider branch name fails Issue created by scrocquesel Version information: • OS: Linux • PactNet Version: 5.0.1 • .Net Version: 8 • Pact Broker Version (if applicable): 2.107.1 Describe the bug Trying to publish test results with provider branch "/refs/head/test", result in an error
    Copy code
    2025-07-10T21:23:11.928119Z ERROR ThreadId(01) pact_verifier::pact_broker: Failed to push branch refs/head/test for provider version test
    2025-07-10T21:23:11.928223Z ERROR ThreadId(01) pact_verifier: Publishing of verification results failed with an error: Link/Resource was not found - Request to pact broker path '/pacticipants/myprovider/branches/refs%2Fhead%2Ftest/versions/test' failed: 404 Not Found. URL: '<https://pactbroker.com/>'
    Steps To Reproduce
    Copy code
    options.PublishResults(brokerConfig.ProviderVersion, publishOptions =>
                        {
                            publishOptions
                                .BuildUri("<http://test>")
                                .ProviderBranch("/refs/head/test");
                        });
    Expected behavior The provider verification result should be published to a branch with a slash. This is a supported value with the pact cli to publish consumer contract. Log Output See above Additional context Replacing
    /
    with
    -
    make it works. pact-foundation/pact-net
    • 1
    • 1
  • g

    GitHub

    07/21/2026, 12:37 AM
    #550 RFC: Support for synchronous messaging Issue created by evoclint Do you intend to implement synchronous messaging? I can see in the roadmap it isn't yet supported for PactNet, if you intend to support it do you have a rough idea when this will be? pact-foundation/pact-net
    • 1
    • 1
  • g

    GitHub

    07/31/2026, 2:20 PM
    #557 [Feature Request] Add support for AsyncAPI references in Message Pact (.reference() method) Issue created by mr-roman-vivint Problem When using PactNet to create Message Pact contracts for AsyncAPI Bi-Directional Contract Testing (BDCT) with Pactflow, there's currently no built-in way to link Message Pact interactions to AsyncAPI operations via the
    comments.references.AsyncAPI
    structure. According to PactFlow's AsyncAPI BDCT documentation, consumer pact files should include operation references like this: { "description": "Message interaction", "comments": { "references": { "AsyncAPI": { "operationId": "receiveUserEvents" } } } } Current State in PactNet PactNet 5.0.1 provides
    IMessageBuilderV4.WithMetadata()
    but does not expose a
    .reference()
    method to add AsyncAPI operation references. Workaround (Verified Working) I manually added the
    comments.references.AsyncAPI
    structure to the generated pact file: { "interactions": [ { "description": "Some interaction", "comments": { "references": { "AsyncAPI": { "operationId": "someOperation" } } }, "metadata": { ... }, "contents": { ... } } ] } After adding this structure manually, PactFlow successfully validated the Message Pact against the AsyncAPI provider specification. This confirms that the feature works end-to-end — PactNet just needs a programmatic way to add these references. Expected Behavior PactNet should support something like this: _pactBuilder .ExpectsToReceive("Some message") .Reference("AsyncAPI", "operationId", "someOperation") // ← Missing .WithJsonContent(new { ... }) .Verify<Message>(...) Or alternatively: _pactBuilder .ExpectsToReceive("Some message") .WithAsyncApiReference("someOperation") // ← Missing .WithJsonContent(new { ... }) .Verify<Message>(...) Use Case This feature is essential for teams using PactFlow's AsyncAPI BDCT approach with .NET Message Pact consumers. Without it, the generated pact files cannot be automatically validated against AsyncAPI provider specifications in Pactflow. Environment • PactNet Version: 5.0.1 • .NET Version: 10.0 • Target: PactFlow AsyncAPI BDCT Thanks in advance! pact-foundation/pact-net
  • g

    GitHub

    08/04/2026, 6:24 PM
    #558 [Bug]: Provider verification with WithMessages fails with "builder error for url (message://...)" due to incorrect URL scheme passed to FFI Issue created by daniloitzep Environment • PactNet version:
    5.0.0
    and
    5.0.1
    • Pact Specification: V3 (
    messages
    ) and V4 (
    asyncMessage
    ) • Framework:
    .NET 8.0
    /
    .NET 10
    • OS: Cross-platform (macOS, Windows, Linux) --- Describe the bug When performing provider verification for an asynchronous message contract using the new unified
    PactVerifier.WithMessages(...)
    builder introduced in PactNet 5.0+, the provider verification instantly fails before executing any message scenario or mapper. The underlying Rust verification engine attempts to send HTTP requests to a URL with the scheme
    message://
    instead of
    http://
    , which causes the internal Rust HTTP client (
    reqwest
    ) to fail immediately with a URL builder error:
    builder error for url (<message://localhost:XXXX/pact-messages>)
    . --- Expected behavior PactNet starts a tiny local HTTP server within the test process (`http://localhost:PORT/pact-messages/`) to host the messaging scenarios. When instructing the native Rust engine to verify the interactions, the verification engine should send POST requests via HTTP to that internal server (`http://localhost:PORT/pact-messages/`), receive the serialized message, and compare fields against the contract. --- Actual behavior & Contradictory Logs The verifier logs reveal the exact contradiction in two sequential lines:
    Copy code
    Starting messaging provider at   <http://localhost:49152/pact-messages/>     <-- PactNet starts HTTP adapter correctly
    Sending request to provider at   <message://localhost:49152/pact-messages/>  <-- Rust FFI engine requests wrong scheme
    Request Failed - builder error for url (<message://localhost:49152/pact-messages>)
    Because reqwest does not recognize message:// as a valid network transport scheme, the HTTP request never leaves the builder phase, failing with zero field comparisons performed.
    
    Root Cause Analysis
    In PactNet 5.0+, when registering the message transport provider via FFI (likely invoking pactffi_verifier_add_provider_transport), two distinct attributes are handled:
    
    protocol: The interaction type (message).
    scheme: The network scheme to physically reach the local verification adapter (http).
    It appears PactNet correctly registers the protocol as "message", but either leaves the scheme undefined or erroneously passes "message" as the scheme as well. Consequently, the native engine defaults to duplicating the protocol name into the URL scheme, building message://localhost:49152/pact-messages/ instead of http://....
    
    Steps to Reproduce
    Create a consumer message test generating a valid message pact (tested with both V3 and V4 specifications).
    Set up a provider test using PactVerifier:
    csharp
    using var verifier = new PactVerifier("MyProvider", config);
    verifier
        .WithMessages(scenarios => scenarios.Add("a sample message", () => MyMessageFactory.Create()), jsonOptions)
        .WithFileSource(pactFilePath)
        .Verify();
    Run the provider test. Notice that none of the scenario factory methods are invoked, and verification terminates immediately with builder error for url (message://...).
    Why this is blocking & tested combinations
    We ran systematic testing across multiple matrix combinations to rule out local configuration issues:
    
    PactNet Versions: Fails identically on 5.0.0 and 5.0.1.
    Contract Formats: Fails identically on both V3 and V4 specs.
    Data/Mapper execution: Confirmed via debugging that scenarios and mappers never get called because the internal POST request fails during URL construction.
    Configuration: PactVerifierConfig does not expose any public knobs to manually override the scheme for messaging transports.
    pact-foundation/pact-net
  • g

    GitHub

    08/10/2026, 11:15 PM
    1 new commit pushed to
    <https://github.com/pact-foundation/pact-net/tree/master|master>
    by JP-Ellis
    <https://github.com/pact-foundation/pact-net/commit/519d86279daba984b78b2cea1d9da453a7d661b6|519d8627>
    - ci: remove unused triage board workflow pact-foundation/pact-net
    thankyou 1
  • g

    GitHub

    08/13/2026, 2:53 PM
    #559 feat: Add AsyncAPI reference support for message pacts (#557) Pull request opened by mr-roman-vivint Closes #557 Summary Implements AsyncAPI reference support for message pacts (#557) Problem PactNet lacked a way to programmatically add AsyncAPI operation references to message interactions, which is required for PactFlow BDCT with AsyncAPI. Solution Added three new methods to IMessageBuilderV4: •
    WithComment(key, value)
    - for custom key-value comments •
    WithTextComment(comment)
    - for text comments array •
    WithAsyncApiReference(operationId)
    - convenience method for AsyncAPI refs Changes • Core implementation in MessageBuilder and drivers • FFI bindings for pactffi_set_comment and pactffi_add_text_comment • Unit, integration, and E2E tests • Updated sample code and documentation • V4 only (V3 doesn't support comments per spec) Testing All 411 tests passing. Added comprehensive test coverage. Breaking Changes None - additive change to IMessageBuilderV4 only. pact-foundation/pact-net
  • g

    GitHub

    09/14/2026, 11:03 AM
    #560 deps(ci): actions updates + macos 15 gh runners Pull request opened by YOU54F 1. Replace deprecated MacOS GitHub Action runners with latest ( macos-15 (arm64) / macos-15-intel (x64) ) 2. Update github actions in ci workflow to latest major tags pact-foundation/pact-net
    • 1
    • 1
  • g

    GitHub

    09/16/2026, 6:57 AM
    1 new commit pushed to
    <https://github.com/pact-foundation/pact-net/tree/master|master>
    by adamrodger
    <https://github.com/pact-foundation/pact-net/commit/783124aa54f1d3f7b71234c1c759f6fef60ce8bb|783124aa>
    - deps(ci): actions updates + macos 15 gh runners pact-foundation/pact-net
  • g

    GitHub

    09/23/2026, 2:05 AM
    #561 chore(ci): remove stale internal workflow Pull request opened by JP-Ellis The new Pact Bot will replace the labelling and triage capabilities, making this workflow redundant. pact-foundation/pact-net
    • 1
    • 1
  • g

    GitHub

    09/23/2026, 3:08 AM
    1 new commit pushed to
    <https://github.com/pact-foundation/pact-net/tree/master|master>
    by JP-Ellis
    <https://github.com/pact-foundation/pact-net/commit/229378fd4d048d570161ac3445681868f1a5cbdd|229378fd>
    - chore(ci): remove stale internal workflow pact-foundation/pact-net
  • f

    Fábio Rodrigues

    09/24/2026, 2:46 PM
    github.com/pact-foundation/pact-net/pull/562, but it needs first merge of github.com/pact-foundation/pact-reference/pull/555
  • g

    GitHub

    09/24/2026, 2:54 PM
    #562 feat: add consumer-side support for synchronous (request/response) messages Pull request opened by fabio-andre-rodrigues Summary PactNet currently only supports writing asynchronous (fire-and-forget) message pacts (
    IPactV4.WithMessageInteractions()
    ). There is no way to write a V4 synchronous (request/response) message pact - the type PactFlow uses for AsyncAPI 3 operations that have a
    reply
    block. The underlying
    pact_ffi
    native library this project wraps already has most of what's needed: •
    pactffi_new_sync_message_interaction
    exists in the native lib, but wasn't yet declared in
    NativeInterop.cs
    • The existing generic
    pactffi_with_body
    /
    pactffi_with_metadata
    FFI functions (already used for HTTP interactions in this codebase) work against a synchronous message interaction handle too, since they take an
    InteractionPart
    (Request/Response) The one missing piece was a way to retrieve the generated (matchers stripped, generators applied) request/response contents of a synchronous message interaction for the consumer test -
    pactffi_message_reify
    only supports async messages. I've proposed
    pactffi_sync_message_generate_contents
    upstream in pact-reference: pact-foundation/pact-reference#555 Changes •
    IPactV4.WithSynchronousMessageInteractions()
    - new entry point, parallel to
    WithMessageInteractions()
    •
    ISyncMessagePactBuilderV4
    /
    ISyncMessageBuilderV4
    /
    IConfiguredSyncMessageVerifier
    - public API mirroring the existing async
    IMessagePactBuilderV4
    /
    IMessageBuilderV4
    /
    IConfiguredMessageVerifier
    , but with separate `WithRequest*`/`WithResponse*` methods for request and response content/metadata •
    SyncMessageInteractionDriver
    /
    SyncMessageBuilder
    /
    SyncMessagePactBuilder
    /
    ConfiguredSyncMessageVerifier
    - internal implementation, following the existing async message classes as closely as possible •
    NativeInterop.NewSyncMessageInteraction
    ,
    NativeInterop.WithMetadata
    (the
    InteractionPart
    -aware variant used for both HTTP and sync messages),
    NativeInterop.SyncMessageGenerateContents
    ConfiguredSyncMessageVerifier.Verify<TRequest, TResponse>
    reads the generated request via
    ISyncMessageInteractionDriver.GenerateContents()
    and passes it to the handler under test; the response content is stored in the pact but not currently asserted against the handler's return value, matching the existing async
    Verify<T>(Action<T>)
    semantics (which likewise doesn't assert anything beyond "the handler didn't throw"). Response-value assertion could be a good follow-up once there's agreement on the right semantics for it. Note: the async message driver/verifier keeps its existing
    Reify()
    naming untouched - only the new synchronous-message members use
    GenerateContents()
    , since that's less reliant on Pact-specific "reify" terminology for callers who don't need to know about it. ⚠️ Depends on an unreleased pact_ffi function This PR depends on
    pactffi_sync_message_generate_contents
    , proposed in pact-reference#555 and not yet in any pact_ffi release. Until that lands: • Everything up to calling `.Verify`/`.VerifyAsync` works today, since it only relies on FFI functions that already exist in the currently pinned pact_ffi version. • `ConfiguredSyncMessageVerifier.Verify`/`VerifyAsync` will throw
    EntryPointNotFoundException
    at runtime, since
    pactffi_sync_message_generate_contents
    isn't in the native library yet. I've marked the one FFI-level integration test (
    FfiIntegrationTests.SyncMessageInteraction_v4_CreatesPactFile
    ) as
    Skip
    for the same reason, to keep CI green. Opening this as a draft to get early feedback on the API shape while the pact-reference PR is reviewed; happy to update the pinned pact_ffi version and un-skip that test once a release is available. Test plan •
    dotnet build
    (all projects) •
    dotnet test tests/PactNet.Tests
    - 166 passed, 1 skipped (the FFI-dependent integration test noted above) • Added
    SyncMessageBuilderTests
    ,
    SyncMessagePactBuilderTests
    ,
    ConfiguredSyncMessageVerifierTests
    mirroring the existing async message test coverage • Documented the new API in
    docs/messaging-pacts.md
    pact-foundation/pact-net
    • 1
    • 1
  • g

    GitHub

    09/29/2026, 1:50 PM
    #563 Marshal.PtrToStringAnsi corrupts non-ASCII FFI output on Windows (mismatches, logs, reified message content) Issue created by CloneOfAlex Several places marshal strings returned from
    pact_ffi
    (which are always UTF-8) using `Marshal.PtrToStringAnsi`: •
    src/PactNet/Drivers/MessageInteractionDriver.cs:71
    (
    Reify()
    ) •
    src/PactNet/Drivers/MockServerDriver.cs:42
    (
    MockServerMismatches()
    ) and
    :55
    (
    MockServerLogs()
    ) •
    src/PactNet/Verifier/InteropVerifierProvider.cs:297
    (verifier output) and
    :307
    (verifier logs) Per Microsoft's docs,
    PtrToStringAnsi
    decodes using the Windows ANSI code page on Windows, but UTF-8 on Unix. Since
    pact_ffi
    always returns UTF-8, any non-ASCII character (accents, £/€, CJK, emoji) in a message body, mismatch description, or log line gets corrupted (mojibake) on Windows. The
    Reify()
    case is the most serious: its output is fed directly into
    JsonSerializer.Deserialize<NativeMessage>
    in
    ConfiguredMessageVerifier.MessageReified<T>()
    , so a message pact with non-ASCII content on Windows either throws a confusing
    PactMessageConsumerVerificationException
    or silently hands the consumer's test handler a corrupted body. Repro: On Windows, define a message pact with
    WithJsonContent(new { name = "café" })
    , then verify it — the reified body comes back mangled. Suggested fix: decode these pointers as UTF-8 explicitly (e.g. read to a null terminator and
    Encoding.UTF8.GetString
    , or a helper that doesn't depend on `Marshal`'s platform-dependent "ANSI" behavior) instead of
    PtrToStringAnsi
    . Filed after a manual code review of the current
    master
    branch (HEAD around 5.0.1 + a handful of commits); happy to help verify a fix.
    pact-foundation/pact-net
  • g

    GitHub

    09/29/2026, 1:51 PM
    #564 MessageInteractionDriver.WithContents ignores the caller-supplied size parameter Issue created by CloneOfAlex
    WithContents(string contentType, string body, uint size)
    in
    src/PactNet/Drivers/MessageInteractionDriver.cs:61-62
    always calls: public void WithContents(string contentType, string body, uint size) => NativeInterop.MessageWithContents(this.interaction, contentType, body, new UIntPtr(0)); It discards the
    size
    argument entirely instead of forwarding it, always passing
    UIntPtr(0)
    to the native
    pactffi_message_with_contents
    call. Every current call site (
    MessageBuilder.WithJsonContent
    →
    this.driver.WithContents("application/json", serialised, 0)
    ) happens to pass
    0
    already, which is why this hasn't surfaced as a visible bug — but the parameter is effectively dead code. Any future caller that computes and passes a real content length will silently have it discarded. Suggested fix: pass
    new UIntPtr(size)
    instead of hardcoding zero. Filed after a manual code review of the current
    master
    branch (HEAD around 5.0.1 + a handful of commits).
    pact-foundation/pact-net
  • g

    GitHub

    09/29/2026, 1:53 PM
    #565 MessageScenarios.Add(Func&lt;IMessageScenarioBuilder, Task&gt;) can deadlock via sync-over-async Issue created by CloneOfAlex
    src/PactNet/Verifier/Messaging/MessageScenarios.cs:72
    blocks on the async
    configure
    delegate with: public IMessageScenarios Add(string description, Func<IMessageScenarioBuilder, Task> configure) { var builder = new MessageScenarioBuilder(description); configure?.Invoke(builder).GetAwaiter().GetResult(); ... } If this runs under a captured
    SynchronizationContext
    (e.g. a WPF/WinForms-hosted provider test process) and the user's async lambda awaits something that needs to resume on that context, this deadlocks the calling thread — the classic sync-over-async trap. The sibling synchronous overloads (
    Add(string, Func<dynamic>)
    and
    Add(string, Action<IMessageScenarioBuilder>)
    ) don't have this risk. Suggested fix: avoid
    GetAwaiter().GetResult()
    here — e.g. make the surrounding call path (`WithMessages`/`PactVerifier`) async, or use
    Task.Run(...).GetAwaiter().GetResult()
    to force the continuation off the captured context (with the usual caveats), or ensure the awaited chain uses
    ConfigureAwait(false)
    throughout. Filed after a manual code review of the current
    master
    branch (HEAD around 5.0.1 + a handful of commits).
    pact-foundation/pact-net
  • g

    GitHub

    10/08/2026, 1:16 PM
    #566 chore(ffi): upgrade to pact-ffi 0.5.10 Pull request opened by YOU54F Updates to the latest pact-ffi. v0.5.x introduces the pact core mock server v2, and client behaviour has differed slightly, which shows up in pact-nets regression suite. With
    libpact_ffi
    0.5.x, a request header configured as separate values can mismatch the single comma-separated value sent by an HTTP client. Clients will be expected to configure the expected header as the joined value instead: .WithHeader("X-Request", "request1, request2") This replaces separate calls such as
    .WithHeader("X-Request", "request1")
    and
    .WithHeader("X-Request", "request2")
    when those values are sent together in one request header. such as .WithHeader("X-Request", "request1") .WithHeader("X-Request", "request2") This is going to change client behaviour so will be a breaking change. According to RFC 7230,
    A sender MUST NOT generate multiple header fields with the same field
    name in a message unless either the entire field value for that
    header field is defined as a comma-separated list [i.e., #(values)]
    or the header field is a well-known exception (as noted below).
    The only valid exception is
    Set-Cookie
    So the client is expected to fold up multiple headers into a single comma separated string, so one could argue this change is correct, and correcting a previous bug. If the client was sending two headers of the same name, with a different value, they would not be honouring the above RFC Not sure what this means for versioning here, minor or major. pact-foundation/pact-net
    • 1
    • 1
  • g

    GitHub

    10/12/2026, 7:08 PM
    #567 fix(verifier): support message-only provider verification Pull request opened by YOU54F Register the internal message proxy with an HTTP base transport, preserve message registration when HTTP is configured later, and accept localhost requests alongside IPv4 loopback. Add unit and provider integration coverage for message-only and mixed transport verification. fixes #530 fixes #544 fixes #558 pact-foundation/pact-net
  • g

    GitHub

    10/12/2026, 7:30 PM
    #568 Flaky test: FfiIntegrationTests.HttpInteraction_v3_CreatesPactFile fails with empty logs because the FFI log buffer is shared and drained by concurrent tests Issue created by max-lancaster Previous issues Searched for
    HttpInteraction_v3_CreatesPactFile
    ,
    Did not expect logs to be empty
    and
    MockServerLogs
    . No prior reports. Version information: • OS: macOS Intel (
    macos-15-intel
    GitHub runner), but the root cause is platform-independent • PactNet Version:
    master
    / PR #551 branch, pact-ffi 0.5.10 • .Net Version: .NET 8.0 • Pact Broker Version (if applicable): n/a Describe the bug
    PactNet.Tests.Drivers.FfiIntegrationTests.HttpInteraction_v3_CreatesPactFile
    fails intermittently in CI with:
    Copy code
    Did not expect logs to be empty.
       at PactNet.Tests.Drivers.FfiIntegrationTests.HttpInteraction_v3_CreatesPactFile() in tests/PactNet.Tests/Drivers/FfiIntegrationTests.cs:line 69
    The underlying cause is that PactNet reads mock server logs and driver logs from a single process-wide FFI log buffer, and reading it is destructive: •
    MockServerDriver.MockServerLogs()
    and
    PactDriver.DriverLogs()
    both call
    pactffi_fetch_log_buffer(null)
    , which reads the
    "global"
    buffer. • In pact_ffi,
    fetch_buffer_contents
    does
    buffer.split().freeze()
    , so every fetch empties the buffer. •
    AbstractPactBuilder.Verify
    /
    VerifyAsync
    call
    PrintLogs
    →
    MockServerLogs()
    in a
    finally
    block on every run, pass or fail. • xUnit runs test classes in parallel, and several classes in
    PactNet.Tests
    drive the real FFI (
    PactExtensionsTests
    ,
    MessagingProviderTests
    ,
    InteropVerifierProviderTests
    ,
    FfiIntegrationTests
    ). So whenever another class's
    Verify
    completes while
    HttpInteraction_v3_CreatesPactFile
    is in the middle of its HTTP round trip, the global buffer is drained before line 68 reads it, and the assertion on line 69 fails. The driver logs printed in the test's
    finally
    block are empty for the same reason. The failing run shows the overlap: in the passing
    ubuntu-latest
    job of the same run,
    FfiIntegrationTests.HttpInteraction_v3_CreatesPactFile
    and
    PactExtensionsTests.WithHttpInteractions_V3_CreatesExpectedPactFile
    finished within 1 ms of each other. The slower Intel macOS runner has the widest window for the race, which is where it was first caught. A side effect of the same design:
    MockServerLogs()
    never actually returns the mock server's own request logs. The mock server threads log under their own
    LOG_ID
    , so those lines land in a per-server buffer that PactNet never reads (
    pactffi_mock_server_logs(port)
    ). What
    MockServerLogs()
    returns today is the driver-call trace output from whichever threads happened to log to
    "global"
    since the last fetch. Steps To Reproduce 1. Run
    dotnet test tests/PactNet.Tests
    repeatedly, ideally on a slow or heavily loaded machine so test classes overlap. 2. Occasionally
    HttpInteraction_v3_CreatesPactFile
    fails with
    Did not expect logs to be empty.
    Failing CI run: https://github.com/pact-foundation/pact-net/actions/runs/38292879712/job/114967624969 (macos-15-intel). Every other job in the matrix passed on the same commit. Expected behavior Tests that read FFI logs should not be affected by other tests running concurrently in the same process. Log Output
    Copy code
    Failed PactNet.Tests.Drivers.FfiIntegrationTests.HttpInteraction_v3_CreatesPactFile [1 s]
      Error Message:
       Did not expect logs to be empty.
      Stack Trace:
         at FluentAssertions.Primitives.StringAssertions`1.NotBeEmpty(String because, Object[] becauseArgs)
         at PactNet.Tests.Drivers.FfiIntegrationTests.HttpInteraction_v3_CreatesPactFile() in /Users/runner/work/pact-net/pact-net/tests/PactNet.Tests/Drivers/FfiIntegrationTests.cs:line 69
      Standard Output Messages:
    
     Driver Logs
     -----------
    Additional context Possible fixes, in increasing order of scope: 1. Drop the
    logs.Should().NotBeEmpty()
    assertion in the integration test. The log content is diagnostic; the FFI calls and the pact file comparison are what the test actually verifies. 2. Put every test class that drives the real FFI into one xUnit collection so they never run concurrently. 3. Make
    MockServerLogs()
    call
    pactffi_mock_server_logs(port)
    so it returns the per-server buffer instead of the shared global one. This is the real fix but changes library behaviour. Note that upstream has
    LOG_ID
    marked
    #[deprecated(note = "This must be moved to the FFI crate")]
    in
    pact_mock_server
    , so the FFI side may change too. Found while working on #551; the failure is unrelated to that PR, the same code paths exist on
    master
    . pact-foundation/pact-net
  • g

    GitHub

    10/16/2026, 5:00 PM
    #533 Raw XML POST not working in V2, V3 and V4. Added test for simple POST interaction with different content types. Pull request opened by vcalatayud Added a test to ensure that POST works with different types of content. XML is failing with V2, V3 and V4. pact-foundation/pact-net
    • 1
    • 1
  • g

    GitHub

    10/16/2026, 5:09 PM
    #548 Add PactNet.Extensions.Grpc package for grpc plugin support Pull request opened by max-lancaster Stacked on #551. Everything except the last commit belongs to #551 and will drop out of this diff when that PR merges. The remaining commit adds the
    PactNet.Extensions.Grpc
    package, which is the reference example of a wrapper library built on the raw plugin API described in docs/plugin-interactions.md. I have read through issue #492 thoroughly and examined the source code and feel that I have a decent understanding of what's involved in adding plugin support, specifically for Grpc. I was able to take @Yousaf Nabi (pactflow.io)'s example and create this PR to get some sample Grpc tests working. I have extracted a
    PactNet.Interop
    package as @adamrodger suggested in Issue #492 . This was not a breaking change since all the classes in this namespace were internal,
    PactNet
    now references this new package and none of the pre-existing interface methods have changed. Extracting this package made it possible to create bare-bones Grpc plugin tests and is effectively a very "raw" way of using any plugin. Perhaps a next step would be to wrap the bare-bones methods in a more fluent "raw" interface in a plugin package similar to implementations in other languages as @Matt (pactflow.io / pact-js / pact-go) suggested. Based on above "raw" tests I was able to refactor and extract shared functionality to create a new
    PactNet.Extensions.Grpc
    library that provides a fluent interface similar to the interfaces for http / rest and asynchronous messaging interactions. An alternative approach here would be to just add
    <InternalsVisibleTo Include="PactNet.Extensions.Grpc" />
    to the PactNet.csproj file but this allows integration of other plugins in repos outside this one so it depends on whether you want to explicitly allow that or not. pact-foundation/pact-net
    • 1
    • 1
  • y

    Yousaf Nabi (pactflow.io)

    10/16/2026, 5:14 PM
    grpc is still coming 🙂 so don't be sad if you see the above pr closed 🙂