How To Fix A Failure
What each failure means, keyed by the text you see. Every message
below is the literal one, from crates/cargo-pwrs/dotnet/Pwrs.Runtime/NativeModule.cs,
crates/pwrs/src/host.rs, crates/cargo-pwrs/src/descriptor.rs and
crates/pwrs-build/src/pwsh.rs.
The crate and cargo-pwrs move together
This is the one to check first. PoWerRuSt, pwrs-sys,
pwrs-macros, pwrs-build and cargo-pwrs are published together
at one version, and a module is built from two halves that both have
to be that version: the crate your code links, and the C# runtime
cargo-pwrs embeds in the module folder. Bumping one alone is the
most common way to a module that will not import.
pwrs_module_init failed with status 4 (runtime ABI 1)The module expects more host vtable entries than the runtime that
built it provides. You updated the PoWerRuSt crate and built with
an older cargo-pwrs. Update the tool:
cargo install cargo-pwrs --forceThe refusal is deliberate and it is the safe direction: the module
checks the table’s size header before using any entry, so an old
runtime is caught at pwrs_module_init rather than by calling
through a slot that is not there. The reverse pairing, an older crate
with a newer tool, works: the table only grows.
descriptor ABI 2 is not supported by this cargo-pwrsThe same skew at build time rather than import time, and only when
the ABI version itself changes rather than merely growing: the crate
writes a descriptor the tool does not read. Update the tool. An ABI
version change also renames the exports (pwrs2_*), so the two
halves cannot be mixed silently.
Two modules in one Windows PowerShell session
Exception calling "ReloadNative" with "0" argument(s): "The type initializer for 'Pwrs.Modules.Gamma.PwrsModule' threw an exception."Seen only in Windows PowerShell 5.1, only on the second of two PWRS
modules imported into one session, and only when that module declares
classes or enums. It means one of the two was built by cargo-pwrs
0.1.8 or earlier and the other by 0.2.0 or later. The first import
works and keeps working; the second is refused. A second module that
declares neither imports and runs beside either.
Windows PowerShell has one load context per process, so the first
module’s Pwrs.Runtime serves every PWRS module imported after it,
and a module’s shell registers its classes and enums with the runtime
it gets. The message the engine prints names only the type
initializer. The cause underneath it is a
System.MissingMethodException naming the runtime member that
registration calls: Pwrs.Factories.Register(UInt32, Func<IntPtr, Object>)
for a module built by cargo-pwrs 0.1.8 or earlier meeting a 0.2.0
runtime, and Pwrs.NativeModule.get_Factories() the other way round.
Rebuild both modules with the same cargo-pwrs. PowerShell 7 gives each
module a load context and a runtime of its own, so there two modules
built by different versions import side by side. Both editions were
measured in every order of a 0.1.8 and a 0.2.0 module, one of the two
declaring classes and an enum and the other neither, on Windows
PowerShell 5.1.26100.9444 and pwsh 7.6.6.
A module that loads everywhere but the snap’s pwsh
Exception calling "ReloadNative" with "0" argument(s): "The type initializer for 'Pwrs.Modules.MyModule.PwrsModule' threw an exception."On Linux, under a pwsh installed as a snap, the same message can come
from the native library itself. The snap’s pwsh runs on the glibc of
the snap’s base, 2.35 for core22, so a library built on a host whose
glibc is newer, and which uses a symbol from it, does not load. The
cause sits three exceptions down, and running the module type’s
initializer again from script brings it back, here for a module named
MyModule:
$shell = [AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GetName().Name -like 'MyModule.Shell.*' }
[System.Runtime.CompilerServices.RuntimeHelpers]::RunClassConstructor($shell.GetType('Pwrs.Modules.MyModule.PwrsModule', $true).TypeHandle)System.DllNotFoundException: .../runtimes/linux-x64/native/libmymodule.so could not be loaded: Unable to load shared library ... /snap/core22/current/lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.39' not foundobjdump -T on the library lists the glibc versions it needs. The
same library loads under a pwsh that runs on the host’s own
libraries, such as Microsoft’s tarball install. Measured on Ubuntu
24.04, whose glibc is 2.39, with the powershell snap’s pwsh 7.6.5, two
of this repository’s examples fail this way. examples/tls’s library
needs GLIBC_2.38 for __isoc23_sscanf and __isoc23_strtol:
aws-lc’s C code calls sscanf and strtol, and glibc 2.38’s headers
send those calls to the __isoc23_ versions for C compiled with
_GNU_SOURCE. examples/hello’s needs GLIBC_2.39 for pidfd_spawnp
and pidfd_getpid, which the Rust standard library links for starting
a process, as hello’s helper cmdlets do. calc and memfs need nothing
past GLIBC_2.34 and load under either.
To load under the snap’s pwsh, build the library against the older
glibc. cargo-zigbuild
links through zig against the glibc whose version follows the target
triple, and cargo pwrs hands such a triple to it:
cargo install cargo-zigbuild --locked
cargo pwrs test --release --target x86_64-unknown-linux-gnu.2.35with zig
on PATH. The package’s
[[bin]] helpers build for the same triple. On the same VM, with zig
0.16.0 and cargo-zigbuild 0.23.4, the tls and hello libraries and
hello’s helper built this way need nothing past GLIBC_2.34, and under
the snap’s pwsh 7.6.5 tls passed 4 of 4, hello 282 of 282 and memfs 11
of 11.
Import fails
pwrs native library hello.dll for win-x64 not found under ...The native library for this platform is missing from the module
folder. cargo pwrs build writes it to
runtimes/<rid>/native/, one per platform; a folder built on one
machine and copied to another carries only that machine’s. Build on
the target, or join the folders with cargo pwrs merge.
C:\Modules\MyModule\runtimes\win-x64\native\mymodule.dll could not be loaded: Windows error 126 (The specified module could not be found). It imports opengl32.dll, which is not on this process's DLL search path.The library is in the module folder, but Windows would not load it, and
the rest of the message says why. With error 126, a DLL the library
imports, or one imported by a DLL it imports, is in none of the folders
this process searches: Windows Server Core has no opengl32.dll, for
one. Install what provides the DLL, or link the library so that it loads
the DLL only when it first calls into it (/DELAYLOAD, with
delayimp.lib) and does without it when it is missing. An API set the
message says this version of Windows does not implement is a part of
Windows that the edition leaves out. With error 193 the message names
the machine the library is built for, or the DLL among its imports that
is not a DLL or is built for another machine, against the machine this
process runs.
Which folders are searched depends on the host. Windows PowerShell and
a pwsh installed from its MSI or zip search the folders on PATH; a
pwsh installed from its MSIX package, as the Microsoft Store installs
it, runs as a packaged app and searches only its own folder, the system
folder and folders the process adds.
Neither searches the module folder, since the library loads from a copy
staged outside it. A message that names a file which exists “in a
folder this process does not search for DLLs” is this case: put the DLL
in a folder the host searches, or delay-load it.
On Linux, FreeBSD and macOS the message is <library> could not be loaded: followed by the runtime’s text, which ends with the dynamic
linker’s and names the file it could not find.
System.EntryPointNotFoundException: pwrs_cmdlet_createThe library was found but is not a pwrs module, or was built from a
crate with no export_module!. Every export in
ABI Reference
is required except
pwrs_module_lifecycle, pwrs_transform_invoke and the three CPU-check
exports, which are optional; a missing one names itself.
Hello needs PowerShell 7.4 or later: its PowerShell 7 half is built against .NET 8, and this is PowerShell 7.3.9 on .NET 7.0.20.The host is a PowerShell 7 older than 7.4. A module’s PowerShell 7
half is compiled against .NET 8’s reference pack and the
System.Management.Automation 7.4 reference, and a host loads it only
when it carries at least those versions; when the loader cannot be
reached on such a host, the module’s script reports this in place of
the missing-type error. Run it in PowerShell 7.4 or later, or in
Windows PowerShell 5.1.
Unable to find type [Pwrs.Bootstrap.Loader].
Could not load file or assembly 'System.Diagnostics.Process, Version=9.0.0.0'A module built by cargo-pwrs 0.2.0 or earlier compiled its PowerShell 7 half against the pwsh that built it, so it references that pwsh’s .NET and does not load on an older one. Measured by a consumer: a module built on pwsh 7.6.6 failed with the first message on 7.5.11, 7.4.20 and FreeBSD’s 7.5.5, and one built on FreeBSD’s 7.5.5 failed with the second on 7.4.20. The cargo-pwrs in this repository compiles that half against .NET 8 on every machine, so rebuilding the module with it removes both.
hello.dll was compiled for instruction-set extensions it cannot use here: this CPU does not offer avx512f, avx512bw, ...The native library was compiled for extensions this CPU lacks, usually
by -C target-cpu=native in RUSTFLAGS or in a cargo config on the
machine that built it. Loading it anyway would end the session at the
first such instruction, so the runtime asks the CPU before running any
of the library’s code and refuses the import instead. cargo pwrs build
warned about it at the time. Build with
RUSTFLAGS='-C target-cpu=x86-64' for a module that loads on any
x86-64 CPU; a module that wants wide instructions picks them at run
time, as How To Use Instruction Sets
shows.
The same message with PWRS_CPU_MAX=<level> withholds ... means the
variable is set in this process and caps what the module may use below
what it was compiled for. The variable is for testing a module’s lower
tiers; unset it, or build the module at the baseline.
Collection was modified; enumeration operation may not execute.The import ran in a runspace of a RunspacePool while another runspace
of the same pool imported a module, this one or any other, whose
manifest names a format or types file. A pool’s runspaces share one
InitialSessionState, and Import-Module adds such a module’s files to
that object’s lists and walks the lists without the lock that guards
the additions. It does so before the module’s own script runs, so no
module can guard against it. Every PWRS module with an output class
names a format file, so it meets this as any other module does.
hello’s cold-import suite met it once on FreeBSD. On Windows in pwsh
7.6.6, eight runspaces importing twelve plain script modules each, with
no PWRS in them, met it in 6 of 10 fresh hosts when the runspaces came
from one pool, and in none of 10 when each runspace had a session state
of its own or the pool imported the modules through its
InitialSessionState.
Import the modules through the pool’s InitialSessionState instead.
The pool imports them into each runspace as it opens it, and opens its
runspaces one at a time, so a pool whose scripts import nothing
themselves does not meet the race:
$iss = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
$iss.ImportPSModule('C:\Modules\Hello\Hello.psd1')
$pool = [System.Management.Automation.Runspaces.RunspaceFactory]::CreateRunspacePool(1, 8, $iss, $Host)
$pool.Open()Runspaces made one by one with RunspaceFactory.CreateRunspace() each
have a session state of their own and share no such list; hello’s
cold-import test imports from eight of those at once.
Building fails
cannot run pwsh: ...cargo pwrs needs pwsh to fetch the C# compiler and to run it, since
the compiler runs inside the pwsh process. Install PowerShell 7, or
point PWRS_PWSH at the executable if it is not on PATH.
neither PWRS_HOME, USERPROFILE nor HOME is set; cannot place the toolchain
no bincore/csc.dll under ...The C# compiler is fetched once into ~/.pwrs/toolchain/ and run on
the runtime pwsh already ships; no .NET SDK is involved. Set
PWRS_HOME to say where it goes, and PWRS_TOOLSET to pin a
different Microsoft.Net.Compilers.Toolset version. Each version
gets its own tree, so switching neither refetches nor mixes two
compilers.
[package.metadata.pwrs] references names System.Text.Json, which neither Microsoft.WindowsDesktop.App.Ref 8.0.31 nor the .NET Framework 4.7.2 reference assemblies carryreferences takes Windows desktop assemblies, by the file name each
has in those two packages. The refusal is a name neither package
carries, usually a misspelling or an assembly .NET 8’s own pack already
holds. For Bitmap, Font and Icon name System.Drawing.Common,
where pwsh keeps them; the Windows PowerShell half has .NET Framework’s
System.Drawing already. See
How To Add Hybrid C#
.
cargo-pwrs: namesake_probe::recurrence::Segment and namesake_probe::grammar::Segment are both declared as Probe.Segment; PowerShell knows one type by one name, compared without regard to case, so give one of them another name
cargo-pwrs: namesake_probe::grammar::Segment is declared as Probe.Segment, which export_module! lists for namesake_probe::recurrence::Segment; PowerShell knows one type by one name, compared without regard to case, so give one of them another nameTwo types carry one #[psclass(name = ...)] or #[psenum(name = ...)],
compared without regard to case as PowerShell compares type names: the
first message when export_module! lists both, the second when it lists
one and the library writes the other, since every class whose values
the library can write leaves a record in it that the build reads.
Rename one; the messages name both by their Rust paths. A class the
library writes that export_module! does not list, under a name of its
own, is a warning instead,
pwrs: <path> is declared as <name> and export_module! does not list it, so writing one fails with PwrsUnknownClass;
list it.
A rebuild does not take effect
The running session holds the library it loaded. cargo pwrs build
writes to the module folder, and the next Import-Module -Force
stages a fresh copy and takes it over; see
How To Reload A Module
. Windows keeps a
mapped file locked, which is why the load is always a staged copy and
the path the build writes stays free. A value made before the reload
is refused by the proxy that holds it rather than read against the
new body.
A cmdlet fails at run time
<your message>A cmdlet’s Err(PsError) is an ordinary non-terminating error: the
engine applies -ErrorAction, and -ErrorVariable collects the
record. .terminating() raises it through ThrowTerminatingError
instead. Nothing about this is special to pwrs, which is the point.
A Rust panic crosses as a terminating error carrying the panic message, and the module keeps working afterward; it is caught at the boundary because unwinding into the runtime is undefined. If you see a panic message as a PowerShell error, the fix is in your Rust, not in the binding.
MethodInvocationException: Exception calling "ReadLine" with "0" argument(s):
"PowerShell is in NonInteractive mode. Read and Prompt functionality is not available."The host cannot prompt. ps.host_ui() reaches $Host.UI, and a host
run with -NonInteractive refuses; the error arrives as a
Pwrs.PwrsException with id PwrsRuntimeError and the engine’s own
text inside it (Windows PowerShell says “Windows PowerShell is in
NonInteractive mode”). A command that must run unattended
should take a parameter that answers the question instead of asking.
The console host answers read_line and prompt_for_choice from
redirected standard input, but not read_line_as_secure_string,
which reads the console device: a script piping input to a command
that asks for a secret waits forever.
this Series is in use by a call already running on this thread; it can be reached again once that call returnsA proxy object was reached from inside an exclusive call into the same
object on the same thread: a method taking &mut self, or a script
block run while a cmdlet holds the object through PsProxy::with_mut.
A &mut self method given its own receiver as a by-value argument is
the common shape, since the argument is read back through the object’s
getters while the method holds the only reference. The object is fine,
and the call was refused rather than handed the value a second time. A
&self method, a property read and a with borrow are shared entries
that nest, so they are never refused this way by each other.
Copy what the script needs out of with, and run the script after the
closure returns. A property read in the same place gives $null
instead of this message, since PowerShell’s property adapter turns a
getter’s exception into $null; see
How To Pass Native Data Between Cmdlets
.
a proxy object of this module was expected, and a System.String was passed
a Hello.Counter was passed where another class, or another module's class, was expectedPsProxy::with or with_mut was reached with an object that is not
the module’s own object of that class. A PsProxy<T> parameter cannot
bind anything else, since the binder checks the type first, so this
comes from a PsProxy made from an arbitrary PsObject with
FromPs, or on Windows PowerShell from another module’s object, which
one runtime there serves as well.
namesake_probe::grammar::Segment is declared as Probe.Segment, which export_module! lists for namesake_probe::recurrence::Segment; PowerShell knows one type by one name, so give one of them another nameA write of a #[psclass] value whose type export_module! does not
list, under a name a listed type carries; its id is PwrsClassNameTaken.
cargo pwrs build refuses such a module, so this reaches a session only
from a library built another way. Each type finds its class by its Rust
type, so the unlisted one has none and the write is refused. List it
under a name of its own. A type whose name nothing lists fails the same
write with PwrsUnknownClass.
The shell exits with a memory allocation message
memory allocation of <n> bytes failedpwsh or powershell.exe printed this and ended. A module asked the
allocator for memory through an allocation that cannot report
failure (Vec::with_capacity, vec![0; n], a push that grows), the
allocator refused, and Rust’s answer to that is to abort the process.
An abort is not a panic: nothing at the boundary can catch it.
The fix is in the module. Memory whose size comes from input is
reserved first with try_reserve or try_reserve_exact, and ?
turns a refusal into an ordinary error record with id
PwrsOutOfMemory and category ResourceUnavailable, after which the
next command runs. PWRS’s own conversions of managed strings, arrays,
hashtables, BigInteger and SecureString values, and every string
parameter, reserve that way.
Two things stay fatal. An infallible allocation anywhere else, in the module or in a crate it uses, still aborts; a custom global allocator that returns null does not help, because Rust answers the null with the same abort. And on Linux, where the kernel overcommits memory by default, a process can be ended by the out-of-memory killer before any allocation reports failure.
Tests fail before they run
PWRS_MODULE is not setThe suite is being run directly rather than through
cargo pwrs test, which sets that variable to the built module
folder. Run the command, or set it yourself and run Invoke-Pester.
pwrs: Pester would not load in Core 7.6.6. Tried: Pester 5.7.1 at C:\Users\me\OneDrive\Documents\PowerShell\Modules\Pester\5.7.1. It said: The cloud file provider is not running. Set PWRS_PESTER_PATH to a Pester module that loads in this host, such as one saved with Save-Module -Name Pester.cargo pwrs test could not import Pester in the host named. A project
with a saved copy at target/pester/Pester uses that; any other takes
the host’s own Pester 4 or later, and “Tried” lists each one found.
“It said” is the import’s own error: a OneDrive copy that the OneDrive
client is not running to download reads as above. Save a copy that
loads, Save-Module -Name Pester -Path <folder>, and set
PWRS_PESTER_PATH to the Pester folder inside it.
Nothing above matches
PWRS_TRACE=1 prints both sides’ counters to stderr every 10000
events and PWRS_TRACE=2 prints every event on the Rust side; see
How To Trace A Module
. It has to be in
the environment the process inherits, because the Rust side reads it
with getenv: setting $env:PWRS_TRACE inside PowerShell was
observed on Linux to reach the managed counters only.
The status codes in every failed with status N message are listed
in ABI Reference
: 1 is a managed
exception, 2 a native panic, 3 a pipeline-thread-only entry called
from another thread, 4 an ABI mismatch, 5 a stopped pipeline.