Fix CS0102: The type already contains a definition (Oxide)
CS0102 means the class declares the same member name twice, so Roslyn stops compiling the plugin. In Oxide plugins this is almost always a field or property that was pasted in a second time, for example two config fields or two timer references. Delete or rename the duplicate and the file compiles again.
Error while compiling ChatTitles: [1] The type 'ChatTitles' already contains a definition for 'PluginConfig' at 23:23
Why it happens
The compiler reads your plugin class as a whole and every member name inside it must be unique. CS0102 is raised when a field, property, method or nested type appears more than once at the same scope. The typical Oxide case is copy-pasting a block from another plugin or from an older version of the same file: a private PluginConfig config; line ends up twice, or two [ChatCommand] members share a name, or a timer field is declared again after a refactor. Roslyn reports the second occurrence first and points at the identifier, which is why the line and column in the console can look correct while the real duplicate sits higher in the file. The message often includes the specific member name, as in 'already contains a definition for config'. Oxide removes the file from the batch and does not load the plugin until the duplicate is gone.
How to fix it
- Read the console line:
The type 'ChatTitles' already contains a definition for 'config' at 22:31. It names the duplicated member. - Search the file for that identifier (case-sensitive in a text editor). Count the declarations at class level, not usages inside methods. Field initialisers and properties both count.
- Keep the declaration that matches the rest of the code. If the two differ, check which type other methods expect before deleting. If both are needed, give one a new name and update its references.
- Watch for merged blocks: two
LoadDefaultConfigbodies in one file usually mean two config fields, and twoUnloadmethods will produce CS0111 instead. - Save the file. Oxide reloads it automatically; run
oxide.reload ChatTitlesto force it. The console showsLoaded plugin ChatTitles v1.0.0 by RustPluginGeneratorwhen the file compiles. A remaining CS0102 lists the next duplicated name, so repeat until the load line appears.
Before and after
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
namespace Oxide.Plugins
{
[Info("ChatTitles", "RustPluginGenerator", "1.0.0")]
[Description("Sends a short configurable title message when a player joins the server")]
public class ChatTitles : RustPlugin
{
private class PluginConfig
{
[JsonProperty("Chat prefix")]
public string Prefix = "[Server]";
[JsonProperty("Join message")]
public string JoinMessage = "Welcome to the server";
}
private PluginConfig config;
private class PluginConfig
{
public string Prefix = "[Server]";
public string JoinMessage = "Welcome to the server";
}
}
}using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
namespace Oxide.Plugins
{
[Info("ChatTitles", "RustPluginGenerator", "1.0.0")]
[Description("Sends a short configurable title message when a player joins the server")]
public class ChatTitles : RustPlugin
{
private PluginConfig config;
private class PluginConfig
{
[JsonProperty("Chat prefix")]
public string Prefix = "[Server]";
[JsonProperty("Join message")]
public string JoinMessage = "Welcome to the server";
}
protected override void LoadDefaultConfig()
{
config = new PluginConfig();
}
protected override void LoadConfig()
{
base.LoadConfig();
try
{
config = Config.ReadObject<PluginConfig>();
if (config == null) throw new Exception();
}
catch
{
PrintWarning("Configuration file is invalid, using defaults");
LoadDefaultConfig();
}
SaveConfig();
}
protected override void SaveConfig() => Config.WriteObject(config);
private void OnPlayerConnected(BasePlayer player)
{
if (player == null || !player.IsConnected) return;
timer.Once(5f, () =>
{
if (player == null || !player.IsConnected) return;
player.ChatMessage(config.Prefix + " " + config.JoinMessage);
});
}
}
}FAQ
Why does the compiler point at a line where the field is only used?
CS0102 is reported at the second declaration of the name, and Roslyn often surfaces the duplicate that sits later in the file. The original declaration can be many lines above. Use your editor's find function on the member name and check every match that is a class-level declaration, not a usage.
Does CS0102 stop other plugins from loading?
No. Oxide removes only the failed file from the compile batch and loads the rest. ChatTitles stays unloaded until the duplicate is fixed, but its config, data and lang files remain on disk. After a successful reload, the saved config is read as usual.
I merged two plugins and now get CS0102 for a method name. What is the difference from CS0111?
CS0102 fires when a field, property or nested type name repeats. CS0111 fires when two methods share a name and the same parameter types. Both come from merged code. Rename one member in each pair, then fix the references your editor flags.
The plugin worked before I edited the config class. Why the error now?
Adding a new field is fine, but if the new field reuses a name already present, the class has two members with that name. Check the nested config class for a field like config or a property named after a JSON key that already exists, and rename or remove one of them.
Different error?
Paste the full console output and get the cause and a fix in plain English.
Open the error explainerSkip the debugging
Generated plugins are compiled before you get them, and compiler errors are fixed automatically.
Generate a plugin2 free plugins a month, no card.
Last updated Oct 26, 2026.
Get plugins that compile first time
Generate