This means there is no way of detecting the difference between an
empty array and the array not being provided at all.
Is this correct?
If shortly - yes.
To understand the reason, we should dig into the .Net Core configuration loading mechanism. Adding every new source, like AddJsonFile() or AddEnvironmentVariables(), actually ads another instance of IConfigurationSource to IConfigurationBuilder. When you finally call IConfigurationBuilder.Build() method, you get instance of IConfigurationRoot, which is essentially a holder for a list of loaded configuration providers:
public interface IConfigurationRoot : IConfiguration
{
IEnumerable<IConfigurationProvider> Providers { get; }
void Reload();
}
Goring further, IConfigurationProvider operates only with configuration key-values pairs:
public interface IConfigurationProvider
{
IEnumerable<string> GetChildKeys(IEnumerable<string> earlierKeys, string parentPath);
IChangeToken GetReloadToken();
void Load();
void Set(string key, string value);
bool TryGet(string key, out string value);
}
IConfigurationProvider does not care at all about any initial structure of your settings, like arrays or sub-sections:

Such mechanism has several advantages:
- You could have different parts of configuration (even for one section) in different sources.
- You could override specific key values of a section (keeping other values for a section) in a different source.
So answer to your question is "Yes", you can't detect the difference between an empty array and missing array through standard configuration mechanism. Initial JSON structure is just lost and configuration is stored as key-value pairs. Empty arrays does not produce any key-value pair in IConfigurationProvider.