[Bug]: Null reference exception in LocalUtils constructor
En3Tho opened this issue · 4 comments
Version
1.43-1.47
Steps to reproduce
Repro steps are somewhat convoluted:
- Use WSL + Docker for windows as container runtime
- Write a basic .net interactive notebook/script to create playwright instance and a browser e.g.
var playwright = await Microsoft.Playwright.Playwright.CreateAsync();
var browser = await playwright.Chromium.LaunchAsync(new()
{
Headless = true,
Args = [ "--start-maximized" ]
});
- Install and run dotnet repl global tool to run that notebook/script e.g.
dotnet repl --run (Resolve-Path ./Playwright.dib)
Expected behavior
Instance of LocalUtils is created without exception or a meaningful exception is thrown
Actual behavior
NullReferenceException
is thrown which is not really good or helpful
Additional context
Below is a full output from notebook. There is an important hint:
pw:channel:recv: {"guid":"","method":"__create__","params":{"type":"LocalUtils","initializer":{},"guid":"localUtils"}}
LocalUtils initializer comes empty and triggers a null-ref inside LocalUtils ctor:
public LocalUtils(ChannelOwner parent, string guid, LocalUtilsInitializer initializer) : base(parent, guid)
{
foreach (var entry in initializer.DeviceDescriptors) // here DeviceDescriptors property is null
{
_devices[entry.Name] = entry.Descriptor;
}
}
I do see a guard from missing LocalUtils here:
internal PlaywrightImpl(ChannelOwner parent, string guid, PlaywrightInitializer initializer)
: base(parent, guid)
{
_initializer = initializer;
_devices = _connection.LocalUtils?._devices ?? new();
...
}
Does it mean that LocalUtils initilizer must come non-empty? If so then a proper check should be done on deserialization from json. Null reference exception simply indicates there is a bug but it doesn't describe a context why it is a bug.
Or can local utils initializer be actually empty? E.g. no devices (not sure what those are in context of playwright).
Output:
│ pw:channel:send: │
│ {"id":1,"guid":"","method":"initialize","params":{"sdkLanguage":"csharp"},"metadata":{"internal":false,"wallTime":1728897344483,"apiName":"Playwright.CreateAsync" │
│ ,"location":{"file":"C:\\projects\\dotnet-repl\\src\\dotnet-repl\\Repl.cs","line":66,"column":13}}} │
│ pw:channel:recv: {"guid":"","method":"__create__","params":{"type":"Android","initializer":{},"guid":"android@5fc151f23d559dfb3325fd0dfc2b9619"}} │
│ pw:channel:recv: │
│ {"guid":"","method":"__create__","params":{"type":"BrowserType","initializer":{"executablePath":"/root/.cache/ms-playwright/chromium-1033/chrome-linux/chrome","na │
│ me":"chromium"},"guid":"browser-type@4e2c07f2279ece98e381576716757f4d"}} │
│ pw:channel:recv: │
│ {"guid":"","method":"__create__","params":{"type":"BrowserType","initializer":{"executablePath":"/root/.cache/ms-playwright/firefox-1364/firefox/firefox","name":" │
│ firefox"},"guid":"browser-type@3084be799274cdb7b5f919436cb93625"}} │
│ pw:channel:recv: │
│ {"guid":"","method":"__create__","params":{"type":"BrowserType","initializer":{"executablePath":"/root/.cache/ms-playwright/webkit-1735/pw_run.sh","name":"webkit" │
│ },"guid":"browser-type@55ed6eac0bae687d2fa5619e996cdcd6"}} │
│ pw:channel:recv: {"guid":"","method":"__create__","params":{"type":"Electron","initializer":{},"guid":"electron@11da7c1ffaebb766de9990b25266217d"}} │
│ pw:channel:recv: {"guid":"","method":"__create__","params":{"type":"LocalUtils","initializer":{},"guid":"localUtils"}} │
│ Microsoft.Playwright.TargetClosedException: Object reference not set to an instance of an object. │
│ ---> System.NullReferenceException: Object reference not set to an instance of an object. │
│ at Microsoft.Playwright.Core.LocalUtils..ctor(ChannelOwner parent, String guid, LocalUtilsInitializer initializer) in /_/src/Playwright/Core/LocalUtils.cs:line │
│ 40 │
│ at Microsoft.Playwright.Transport.Connection.CreateRemoteObject(String parentGuid, ChannelOwnerType type, String guid, Nullable`1 initializer) in │
│ /_/src/Playwright/Transport/Connection.cs:line 365 │
│ at Microsoft.Playwright.Transport.Connection.Dispatch(PlaywrightServerMessage message) in /_/src/Playwright/Transport/Connection.cs:line 280 │
│ --- End of inner exception stack trace --- │
│ at Microsoft.Playwright.Transport.Connection.InnerSendMessageToServerAsync[T](ChannelOwner object, String method, Dictionary`2 dictionary, Boolean keepNulls) │
│ in /_/src/Playwright/Transport/Connection.cs:line 206 │
│ at Microsoft.Playwright.Transport.Connection.WrapApiCallAsync[T](Func`1 action, Boolean isInternal) in /_/src/Playwright/Transport/Connection.cs:line 526 │
│ at Microsoft.Playwright.Transport.Connection.InitializePlaywrightAsync() in /_/src/Playwright/Transport/Connection.cs:line 245 │
│ at Microsoft.Playwright.Playwright.CreateAsync() in /_/src/Playwright/Playwright.cs:line 64 │
│ at Submission#5.<<Initialize>>d__0.MoveNext()
Environment
- Operating System: WSL/ Ubuntu 22.04
- CPU: x64
- .NET Version (TFM): net8.0
It looks like you still have some very old Playwright cached somewhere, since the protocol logs show that its offering Chromium 1033 which corresponds to Playwright 1.28 while you connect with a more modern Playwright (1.43ish). So maybe try to purge some .NET interactive caches? Most likely its some old bin
/obj
folder somewhere.
I wonder where it is coming from because I do have chromium-1134 ffmpeg-1010
in /root/.cache/ms-playwright
. I did a clean install of playwright@1.47
and it is still weirdly reporting that. It is also happening when installing using a dontet build
+ install.ps1
combination. I wonder if I do in fact have some garbage cached in docker itself that somehow gets into container
I'm unfortunately not familiar with dotnet-repl, it seems to be using Microsoft.DotNet.Interactive.CSharp
- so maybe it has a cache somewhere.
I'd try deleting ~/.nuget/packages
as per here. Are you able to share a full reproduction? Ideally a Dockerfile which we can run? Does it reproduce there?
@mxschmitt Sorry for the delayed response. You were right: dotnet repl
bundles an old playwright version. Using driver search path env variable fixed the issue.
It is also worth noting that dotnet repl
has lots of problems and I ended up using dotnet script
instead as it's much more stable and easier to work with