JeffreySu/WeiXinMPSDK · error · ArgumentException

AppId 不能为空。

Error message

AppId 不能为空。

What it means

RegisterWithCredentialProviderAsync validates its inputs up front and throws ArgumentException('AppId 不能为空。') when the appId parameter is null, empty, or whitespace. Registration cannot proceed without an identity to key the cache and callbacks on.

Solutions

  1. Supply a valid non-empty appId to RegisterWithCredentialProviderAsync.
  2. Validate/trim the appId at the call site before invoking registration.
  3. Fix the upstream data source (config key, DB row) that produced the empty value.
  4. Add a startup sanity check that enumerates tenants/appIds and fails early if any is blank.

Example fix

// before
await AccessTokenContainer.RegisterWithCredentialProviderAsync(tenant.AppId, provider); // AppId may be empty
// after
if (string.IsNullOrWhiteSpace(tenant.AppId))
    throw new InvalidOperationException($"Tenant {tenant.Id} has no AppId configured.");
await AccessTokenContainer.RegisterWithCredentialProviderAsync(tenant.AppId, provider);
Defensive patterns

Strategy: validation

Validate before calling

if (string.IsNullOrWhiteSpace(appId))
    throw new InvalidOperationException("Cannot register credential provider: appId is null or empty.");
await AccessTokenContainer.RegisterWithCredentialProviderAsync(appId, provider);

Type guard

bool CanRegister(string appId) => !string.IsNullOrWhiteSpace(appId);

Try / catch

try
{
    await AccessTokenContainer.RegisterWithCredentialProviderAsync(appId, provider);
}
catch (ArgumentException ex) when (ex.ParamName == nameof(appId))
{
    _logger.LogError(ex, "Registration rejected: appId for tenant {TenantId} is empty.", tenant.Id);
    throw;
}

Prevention

When it happens

Trigger: Calling AccessTokenContainer.RegisterWithCredentialProviderAsync(null/'', credentialProvider) — e.g. an appId sourced from an unset configuration entry, a failed tenant lookup, or a variable defaulted to empty.

Common situations: Multi-tenant setups where a tenant's appId column is empty in the database; config binding that silently yields empty strings; code paths that pass an uninitialized variable straight into registration.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of JeffreySu/WeiXinMPSDK@be573f6f94 (2026-09-12). Data as JSON: /api/errors/ee5cc9aff29e31b0. Report an issue: GitHub.

Appendix: source

Thrown at src/Senparc.Weixin.MP/Senparc.Weixin.MP/Containers/AccessTokenContainer.cs:287

            //为JsApiTicketContainer进行自动注册
            var registerJsApiTask = JsApiTicketContainer.RegisterAsync(appId, appSecret, name);

            await Task.WhenAll(new[] { registerTask, registerJsApiTask }).ConfigureAwait(false);//等待所有任务完成
        }

        /// <summary>
        /// 使用外部凭据提供器注册 AccessToken。自动重注册委托只捕获提供器,不长期捕获明文 AppSecret。
        /// 此入口仅注册 AccessToken;如需 JS-SDK Ticket,请为对应容器单独配置凭据提供器。
        /// </summary>
        public static async Task RegisterWithCredentialProviderAsync(
            string appId,
            IWeixinCredentialProvider credentialProvider,
            string name = null,
            CancellationToken cancellationToken = default)
        {
            if (string.IsNullOrWhiteSpace(appId))
            {
                throw new ArgumentException("AppId 不能为空。", nameof(appId));
            }

            if (credentialProvider == null)
            {
                throw new ArgumentNullException(nameof(credentialProvider));
            }

            SetRegistrationCallback(appId, async () =>
            {
                var secret = await credentialProvider.GetSecretAsync(appId, CancellationToken.None).ConfigureAwait(false);
                if (string.IsNullOrWhiteSpace(secret))
                {
                    throw new InvalidOperationException("凭据提供器返回了空 AppSecret。");
                }

                var bag = new AccessTokenBag
                {
                    Name = name,

View on GitHub (pinned to be573f6f94)