{"record":{"id":"36ee55f0d360bd63","repo":"github/copilot-sdk","slug":"copilotclientoptions-builtinplugindirectories-must","errorCode":null,"errorMessage":"CopilotClientOptions.BuiltinPluginDirectories must contain only absolute paths: <path>","messagePattern":"CopilotClientOptions\\.BuiltinPluginDirectories must contain only absolute paths: <path>","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"dotnet/src/Client.cs","lineNumber":146,"sourceCode":"    /// // Connect to an existing runtime\n    /// var client = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForUri(\"localhost:3000\") });\n    ///\n    /// // Custom runtime path with specific log level\n    /// var client = new CopilotClient(new CopilotClientOptions\n    /// {\n    ///     Connection = RuntimeConnection.ForStdio(path: \"/usr/local/bin/copilot\"),\n    ///     LogLevel = CopilotLogLevel.Debug\n    /// });\n    /// </code>\n    /// </example>\n    public CopilotClient(CopilotClientOptions? options = null)\n    {\n        _options = options ?? new();\n        _connection = _options.Connection ?? ResolveDefaultConnection(_options);\n        _builtinPluginDirectories = _options.BuiltinPluginDirectories?.ToArray() ?? [];\n        foreach (var path in _builtinPluginDirectories.Where(path => !IsFullyQualifiedPath(path)))\n        {\n            throw new ArgumentException(\n                $\"{nameof(CopilotClientOptions)}.{nameof(CopilotClientOptions.BuiltinPluginDirectories)} \" +\n                $\"must contain only absolute paths: {path}\",\n                nameof(options));\n        }\n\n        switch (_connection)\n        {\n            case StdioRuntimeConnection:\n                break;\n\n            case InProcessRuntimeConnection:\n                break;\n\n            case TcpRuntimeConnection tcp:\n                if (tcp.ConnectionToken is { Length: 0 })\n                {\n                    throw new ArgumentException(\"ConnectionToken must be a non-empty string or null.\", nameof(options));\n                }","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/dotnet/src/Client.cs#L128-L164","documentation":"The CopilotClient constructor validates that every entry in CopilotClientOptions.BuiltinPluginDirectories is an absolute (fully qualified) path. Any relative path causes an immediate ArgumentException naming the offending path.","triggerScenarios":"new CopilotClient(options) where options.BuiltinPluginDirectories contains a relative path like \"plugins\" or \"./builtin\" or \"~/.copilot/plugins\".","commonSituations":"Hardcoding relative paths in app config; relying on '~' expansion which .NET does not perform; configs authored on one OS and reused on another; test fixtures using relative paths that worked via the working directory elsewhere.","solutions":["Convert each directory to an absolute path with Path.GetFullPath(Path.Combine(baseDir, rel)) before assigning","Expand '~' yourself via Environment.GetFolderPath for user-relative dirs","Fix the configured value in appsettings/config to a fully qualified path"],"exampleFix":"// before\noptions.BuiltinPluginDirectories = new[] { \"plugins/builtin\" };\n// after\noptions.BuiltinPluginDirectories = new[] { Path.GetFullPath(\"plugins/builtin\", AppContext.BaseDirectory) };","handlingStrategy":"validation","validationCode":"if (dirs.Any(d => !Path.IsPathFullyQualified(d))) throw new ArgumentException(\"BuiltinPluginDirectories must all be absolute\");","typeGuard":null,"tryCatchPattern":"try { client = new CopilotClient(options); } catch (ArgumentException ex) when (ex.Message.Contains(\"absolute paths\")) { log.LogError(ex, \"Plugin dir config invalid\"); }","preventionTips":["Run Path.GetFullPath on every configured directory","Expand '~' yourself; .NET does not expand it","Assert absolute paths in options tests"],"tags":["dotnet","validation","paths"],"backgroundTag":"invalid-argument-value","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}