Skip to content

Xcode Build Error: Duplicate interface definition for CAPHttpPlugin with latest @capacitor/ios and @capacitor/http #2377

@cathrynhickok

Description

@cathrynhickok

Bug Report

Plugin(s)

@capacitor/http 7.2.0
@capacitor/ios 7.2.0

Capacitor Version

💊 Capacitor Doctor 💊

Latest Dependencies:

@capacitor/cli: 7.2.0
@capacitor/core: 7.2.0
@capacitor/android: 7.2.0
@capacitor/ios: 7.2.0

Installed Dependencies:

@capacitor/cli: 5.7.8
@capacitor/core: 5.7.8
@capacitor/android: 5.7.8
@capacitor/ios: 5.7.8

[success] iOS looking great! 👌
[success] Android looking great! 👌

Platform(s)

IOS

Current Behavior

When using the latest versions of all @capacitor/ packages (core, cli, ios) and installing the latest standalone @capacitor/http plugin, the Xcode build fails after running npx cap sync.

The specific error is:
.../node_modules/@capacitor/http/ios/Plugin/Plugin.m:4:1: error: duplicate interface definition for class 'CAPHttpPlugin'

The build log indicates the "previous definition is here" pointing to a path within the core Capacitor.framework/Headers/Capacitor-Swift.h. This strongly suggests that the native code for the HTTP plugin is now bundled within the core @capacitor/ios framework, and the pod specification from the standalone @capacitor/http package is creating a conflict.

Expected Behavior

The Xcode project should build successfully after installing @capacitor/http and running npx cap sync. The JavaScript bridge provided by the @capacitor/http npm package should allow for native HTTP requests to be made without native build conflicts.

Code Reproduction

A minimal reproduction can likely be created with the following steps:

Create a new project with a web framework (e.g., SvelteKit, Next.js, or even a simple HTML/JS setup).
Initialize Capacitor in the project: npx cap init [appName] [appId]
Install the latest Capacitor core dependencies:
npm install @capacitor/cli@latest @capacitor/core@latest @capacitor/ios@latest

Install the latest official HTTP plugin:
npm install @capacitor/http@latest

Add the iOS platform:
npx cap add ios

Sync the project:
npx cap sync

Open the generated iOS project in Xcode:
npx cap open ios

Attempt to build the project for a simulator or device.

Other Technical Details

Node.js Version: v22.14.0
NPM Version: 10.9.2
Xcode Version: Version 16.3
macOS Version: Sequoia 15.3.1
Project Framework: SvelteKit with Vite (though the issue appears to be at the native iOS build level, independent of the web framework).

Additional Context

This issue was encountered during an extensive debugging process to enable native HTTP requests for a Supabase backend, specifically to bypass CORS issues in a Capacitor mobile app (as Supabase seems to have removed UI-based CORS configuration for wildcard origins like capacitor://localhost).

Key Observations from Debugging:

The Podfile generated by npx cap sync correctly includes the line pod 'CapacitorHttp', :path => '../../node_modules/@capacitor/http' when the @capacitor/http npm package is installed.
The Xcode error message explicitly points to the Plugin.m from the CapacitorHttp pod and the Capacitor-Swift.h from the core Capacitor.framework as the sources of the duplicate definition.
Workaround 1 (Native Build Success, Runtime JS Failure): Manually removing the pod 'CapacitorHttp' line from the Podfile (after npx cap sync) and then running pod install allows the native Xcode project to build successfully. However, this breaks the JavaScript bridge:
If the @capacitor/http npm package is uninstalled (to prevent npx cap sync from re-adding the pod line), then import { CapacitorHttp } from '@capacitor/http'; fails, and Capacitor.Plugins.Http is undefined at runtime.
If the @capacitor/http npm package is installed but the pod line is manually removed, import { CapacitorHttp } from '@capacitor/http'; (static or dynamic) still results in an undefined plugin object at runtime, suggesting the JS bridge relies on the pod being registered.
Successful Workaround (Using Older Capacitor Ecosystem): The only way to achieve a working application (both build and runtime) was to downgrade the entire Capacitor ecosystem to version 5 and use the older @capacitor-community/http@^1 plugin with a dynamic import() in JavaScript:
Bash

npm install @capacitor/cli@5 @capacitor/core@5 @capacitor/ios@5 @capacitor/android@5 @capacitor/preferences@5 @capacitor-community/http@^1
And in the client-side JavaScript:
JavaScript

// Inside an async function on a native platform
const { Http } = await import('@capacitor-community/http');
await Http.request(...);
This strongly suggests an issue specific to the latest (v6+) versions of Capacitor and how the @capacitor/http plugin interacts with the core @capacitor/ios framework.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions