router-for-me/CLIProxyAPI · error

cliproxy_plugin_init returned %d: %v

Error message

cliproxy_plugin_init returned %d: %v

What it means

On Windows, the host resolves and calls the cliproxy_plugin_init export in the plugin DLL via syscall; a nonzero return code triggers this error. It means the plugin's initialization function itself failed (the errCall component is the syscall.LastError, usually not the plugin's reason). The client is closed via closeAfterOpenFailure.

Source

Thrown at internal/pluginhost/loader_windows.go:105

	id := windowsHostCallbackID.Add(1)
	hostCtx := new(uintptr)
	*hostCtx = id
	windowsHostCallbackEntries.Store(id, dynamicHostCallbackEntry{host: host, pluginID: file.ID})
	client := &dynamicLibraryClient{
		dll:      dll,
		tempPath: loadPath,
		hostCtx:  hostCtx,
		hostAPI: &windowsHostAPI{
			abiVersion: pluginHostABIVersion,
			hostCtx:    uintptr(unsafe.Pointer(hostCtx)),
			call:       windowsHostCallCallback,
			freeBuffer: windowsHostFreeCallback,
		},
	}
	rc, _, errCall := proc.Call(uintptr(unsafe.Pointer(client.hostAPI)), uintptr(unsafe.Pointer(&client.api)))
	if rc != 0 {
		client.closeAfterOpenFailure()
		return nil, fmt.Errorf("cliproxy_plugin_init returned %d: %v", rc, errCall)
	}
	if client.api.abiVersion != pluginHostABIVersion {
		client.closeAfterOpenFailure()
		return nil, fmt.Errorf("plugin ABI version %d is not supported", client.api.abiVersion)
	}
	if client.api.call == 0 || client.api.freeBuffer == 0 {
		client.closeAfterOpenFailure()
		return nil, fmt.Errorf("plugin function table is incomplete")
	}
	return client, nil
}

func shadowCopyPlugin(file pluginFile) (string, error) {
	dir, errDir := shadowPluginDir()
	if errDir != nil {
		return "", errDir
	}
	shadowPluginCleanupOnce.Do(func() {

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Test the DLL in isolation (rundll32 or a small harness) to see whether cliproxy_plugin_init succeeds and which dependency fails
  2. Rebuild the plugin with the same toolchain/architecture (GOARCH amd64 vs 386) as the host process
  3. Place dependent DLLs alongside the original plugin artifact or link the plugin statically
  4. Rebuild the plugin against the pluginhost SDK version matching the server
Defensive patterns

Strategy: try-catch

Try / catch

client, err := loader.Open(file, host)
if err != nil {
    log.WithError(err).WithField("plugin", file.Path).Error("plugin init failed")
    continue // skip plugin, keep server up
}

Prevention

When it happens

Trigger: DLL's init returns nonzero because of missing runtime dependencies (VC++ redistributable), failed internal initialization, architecture mismatch (32-bit DLL in 64-bit host), or the DLL not actually exporting a working cliproxy_plugin_init.

Common situations: Plugin compiled with a different toolchain than expected; dependent DLLs not next to the shadow-copied plugin; plugin built for a different ABI of the plugin SDK whose init rejects the host API struct.

Related errors


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/f8960e51d51c1cb1. Report an issue: GitHub.