RayWangQvQ/BiliBiliToolPro · critical · InvalidOperationException
Unable to get SqliteConfigurationProvider
Error message
Unable to get SqliteConfigurationProvider
What it means
HandleValidSubmitAsync in the Blazor config page saves settings through the SqliteConfigurationProvider obtained from the app's IConfigurationRoot. If the provider cannot be resolved (GetSqliteConfigurationProvider() returns null) it throws InvalidOperationException('Unable to get SqliteConfigurationProvider'), meaning the in-memory configuration does not contain the SQLite config source that must back persisted settings.
Solutions
- Ensure startup adds the SQLite configuration source (the AddSqliteConfig/extension used by the default Program.cs) before the Blazor app runs.
- Verify the SQLite database file path exists and the process has write permission to it.
- Check GetSqliteConfigurationProvider(): iterate configurationRoot.Providers and confirm a SqliteConfigurationProvider is present; fix the detection logic if the type changed after a refactor.
- Run with the stock Program.cs/host builder to confirm default behavior, then re-apply customizations.
Example fix
// before
var sqliteProvider = GetSqliteConfigurationProvider();
if (sqliteProvider == null)
throw new InvalidOperationException("Unable to get SqliteConfigurationProvider");
// after (log available providers to diagnose, fail with context)
var providers = ((IConfigurationRoot)Configuration).Providers.Select(p => p.GetType().Name);
logger.LogError("No SqliteConfigurationProvider. Loaded: {Providers}", string.Join(",", providers));
throw new InvalidOperationException($"Unable to get SqliteConfigurationProvider. Loaded: [{string.Join(\",\", providers)}]"); Defensive patterns
Strategy: validation
Validate before calling
var root = (IConfigurationRoot)Configuration;
bool hasSqlite = root.Providers.Any(p => p is SqliteConfigurationProvider);
if (!hasSqlite)
logger.LogError("SQLite配置源未注册,无法保存配置"); Try / catch
try { await HandleValidSubmitAsync(); }
catch (InvalidOperationException ex)
{
message = $"保存失败:{ex.Message}。请确认应用以默认启动方式运行(包含SQLite配置源)";
} Prevention
- Always start the Web app via the stock Program.cs that registers the SQLite source
- Ensure the SQLite DB path is writable by the process
- After startup refactors, verify Providers still include SqliteConfigurationProvider
- Surface provider diagnostics in the config page on failure
When it happens
Trigger: The host was built without the SQLite configuration source being added (e.g. AddSqliteConfig not invoked or DB path misconfigured), the IConfigurationRoot has no provider whose type is SqliteConfigurationProvider, or the page is rendered in an environment (test host, alternate startup) that constructs configuration differently.
Common situations: Running the Web UI with a custom Program.cs that omits the SQLite config registration; DB file path unwritable so provider initialization silently failed; upgrading the app with a startup refactor that dropped the provider.
Related errors
- SqliteConfigurationProvider not found
- IConfigurationRoot not available — cannot access Providers…
- 获取青龙token失败
- 未配置白虎API Token
AI-assisted analysis of RayWangQvQ/BiliBiliToolPro@c599b2c0da (2026-09-12).
Data as JSON: /api/errors/81924265abc5bb14.
Report an issue: GitHub.
Appendix: source
Thrown at src/Ray.BiliBiliTool.Web/Components/Pages/Configs/BaseConfigComponent.cs:81
_isLoading = false;
StateHasChanged();
}
return Task.CompletedTask;
}
protected virtual async Task HandleValidSubmitAsync()
{
_isLoading = true;
_saveMessage = null;
try
{
// 保存配置
var sqliteProvider = GetSqliteConfigurationProvider();
if (sqliteProvider == null)
{
throw new InvalidOperationException("Unable to get SqliteConfigurationProvider");
}
var configValues = _config.ToConfigDictionary();
sqliteProvider.BatchSet(configValues);
// 如果有对应的定时任务,同步更新 Quartz 任务状态和 Cron 表达式
var jobKey = GetJobKey();
if (jobKey != null && SchedulerService != null)
{
// 更新 Cron 表达式
await UpdateJobCronAsync(jobKey, _config.Cron);
// 控制任务启停
await ControlScheduledJobAsyc(jobKey, _config.IsEnable);
}
_saveMessage = GetSaveSuccessMessage();
_saveSuccess = true;View on GitHub (pinned to c599b2c0da)