Version 2.13 Known Issues

Version 2.13.0b0

  • GitHub issue 1226: Fixed C++ output redirection and message lifetimes, restoring shared OpNav outputs affected since 2.12.0. Message-vector access now preserves the correct source owner across later module imports, preventing premature deletion and false deleted-module errors.

  • Configure redirection before connecting readers or recorders, and keep modules alive during simulation. Use stand-alone gateways for redirected feedback; native ownership cycles remain unsupported and are not automatically detected. Redirecting through raw pointer-vector copies or slices raises ReferenceError; use the original module output or a Python list selection. Keep the module’s output-vector entries intact.

  • Camera and Vizard image buffers are valid only until the producer replaces them. Message recorders do not archive image bytes; save images or copy their bytes while current.

  • Fixed Python iterator crashes and numeric-vector access errors that depended on module import order, including storage-message reads and C++ Module: linkBudget lookup tables.

  • GitHub issue 1632: C++ Module: linkBudget underestimated atmospheric attenuation on Earth-space slant paths by repeatedly applying a ground-to-layer refraction ratio to the running elevation cosine. Each layer now uses the ground ray invariant and its own elevation when accumulating loss. Atmospheric layer generation also produced nearly constant one-meter steps and overflowed near 72.4 km for a sea-level station, silently stopping below the intended 100 km limit. A finite exponential grid now covers the complete altitude interval and samples atmospheric properties at layer midpoints. Cells are split at the atmosphere’s temperature and pressure formula boundaries to reduce absolute attenuation errors near absorption lines. The resulting sea-level grid uses 931 cells instead of 70,979. Absolute attenuation regression tests use real oxygen and water-vapor absorption tables and a converged fine-grid reference. A committed reference-generation utility reproduces the 1 m versus 0.5 m convergence comparison. Quantitative tests cover the existing per-layer sine clamp of 0.0872, including low elevations and both sides of its threshold; clamp behavior is unchanged.

  • The classical orbital-element choice in C++ Module: formationBarycenter, including the implementation in tagged release 2.12.0, can place a reference far from a compact near-circular formation because separately averaged classical angles are singular. This choice remains unchanged for compatibility. Select the new prograde or retrograde mean-longitude equinoctial option for supported elliptic formations, or use the existing Cartesian method when a physical center of mass is required. Each equinoctial representation excludes one equatorial pole; non-elliptic inputs and undefined circular-mean longitudes are rejected rather than silently falling back.

  • C Module: headingSuKF applied the inverse camera mounting rotation when writing r_BN_C, producing incorrect camera-frame headings for rotated cameras. It now uses the body-to-camera rotation defined by sigma_CB.

  • C Module: pixelLineConverter, C Module: horizonOpNav, and C Module: faultDetection republished retained valid measurements with new output timestamps, which could prevent downstream C Module: opNavPoint timeout. They now consume each input write once, preserve the output and its timestamp between writes, and publish invalid output when new inputs provide no usable measurement. This allows slower consumers to read valid observations without continually refreshing their age. Fault detection checks freshness independently for its primary and secondary inputs; mode 2 requires both to be fresh in the same update.

  • GitHub issue 1657: C Module: opNavPoint wrote a principal rotation axis in camera frame components into the body-relative attitude error sigma_BR, including the 180 degree fallback axis. The commanded rotation was correct only when the camera frame coincided with the body frame (sigma_CB = [0, 0, 0]); any other camera mounting rotated the spacecraft about the wrong axis.

  • C Module: opNavPoint treated a retained valid=1 message as a new image on every update, preventing timeout and reinterpreting its camera vector with the current attitude. The module now accepts each valid message write time once and reuses the saved inertial heading until it expires.

  • C Module: opNavPoint used lastTime == 0 to mark that no heading was saved. The heading of a valid image at simulation time 0 was therefore discarded on the next update, and the module switched to the search rate if the following image was invalid. A valid image that arrived exactly timeOut seconds after the previous one was also ignored for one update, and with the default timeOut of zero, valid images were never used.

  • In Basilisk 2.12.1, a failed Monte Carlo data writer can leave incomplete combined dataframes without reporting an error to the caller; initial-condition runs can also wait indefinitely for queued data. The controller now detects writer exit, raises RuntimeError, and cleans up its workers and queue manager. Treat partial archives from failed or interrupted campaigns as incomplete and rerun after resolving the writer error.

  • C Module: thrForceMapping could return positive commands during off-pulsing because its second unconstrained solve could reverse a selected thruster’s sign. Such results now trigger a nonnegative least-squares fallback over all configured thrusters, followed by force-norm minimization at fixed achieved torque. Roundoff-sized positive commands are clamped to zero. This also avoids weak-thruster and proportional-column selection artifacts. Row-space projection prevents cycling at zero-force boundaries. Valid allocations and the existing angErrThresh saturation policy are retained.

  • GitHub issue 1658: C Module: thrForceMapping compared the commanded torque reduced onto the control axes, expressed in control axis components, with the thruster torque expressed in body frame components. For control axes other than the leading rows of the identity matrix (for example permuted, non-leading, or rotated axes) the outTorqAngErr output was wrong and the angErrThresh saturation scaling could be applied or skipped incorrectly, so the same torque request produced different thruster forces depending only on the control axis order.

  • Editable installs and wheel builds could hang during Git source discovery on macOS. Packaging now avoids the pipe deadlock without requiring dependency downgrades.

  • GitHub issue 1654: Some Apple Silicon Rust toolchains, including 1.99.1, report rust-objcopy debug-stripping failures because libLLVM.dylib is missing from the tool’s library search path. Compilation and tests can still succeed despite these warnings. Rust-enabled macOS CI and wheel jobs now install the selected toolchain’s matching llvm-tools-preview component and verify direct tool execution and debug stripping before building. Local source builds need the same component; see Setup On macOS for installation and verification commands.

  • C++ Module: lambertSolver silently returned invalid solutions for unknown solverMethod values. The message now carries the selection as a raw integer, and values other than IZZO (0) or GOODING (1) raise BasiliskError before conversion to the internal enum or publication of a new output. Corrected requests recover without resetting the module, and zero-initialized messages retain the Izzo default.

  • C++ Module: lambertSolver could accept nonfinite flight time or gravity, unusable endpoint vectors, and invalid alignment thresholds, allowing invalid arithmetic or bypassing the transfer-plane check. Numeric inputs are now validated before solving and invalid values raise BasiliskError. setAlignmentThreshold now accepts only finite values strictly between 0 and 90 degrees, preserving its previous value when a new value is rejected. A componentwise roundoff bound rejects parallel and antiparallel endpoints even when normalization produces a tiny nonzero cross product and the configured angular threshold would otherwise allow it. Alignment rejection occurs before computing lambda and the scaled flight time, avoiding invalid square roots or division by zero for rejected collinear geometry.

  • An aligned input to C++ Module: lambertSolver could permanently disable solutions on that module instance, even after a later input defined a valid transfer plane. Alignment rejection now applies only to the current update. Both solution and performance slots are cleared for a rejected input, and later acceptable geometry or a relaxed alignment threshold can recover without resetting or recreating the module.

  • The Izzo method in C++ Module: lambertSolver used an incorrect exponent for its intermediate zero-revolution starter, producing a negative guess for a positive root. The corrected logarithmic interpolation is continuous at both ends of the interval and reduces unnecessary safeguarded iterations. Some transfers near the parabolic boundary previously exceeded the default C++ Module: lambertValidator iteration limit despite converging to a valid root. The Python test reference uses the corrected exponent as well and safely refines starters at the parabolic boundary without producing NaN results.

  • C++ Module: lambertSolver could publish unconverged roots as valid after reaching its iteration limit, including short transfers and multi-revolution transfers just above the minimum time. Root searches now use safeguarded branch brackets and require finite results, a small final step, and a small flight-time residual. A failed branch returns zero velocities with its validity flag cleared; a later resolvable request can recover. Accurate hyperbolic starters and converged tiny corrections are retained to avoid unnecessary bisection and downstream iteration-limit rejection. Step-shrink checks compare consecutive high-order steps; bisection clears that history so high-order refinement can resume. Parabolic solutions use the same residual tolerance; nearby flight times use a smooth evaluator instead of a constant approximation. Requests beyond the evaluator’s numerical resolution can still be rejected.

  • GitHub issue 1652: C++ Module: lambertSolver previously assumed prograde motion about the input frame’s positive z-axis, so retrograde problems could return the opposite transfer with a valid flag. LambertProblemMsgPayload.transferDirection now selects PROGRADE (the zero/default value) or RETROGRADE for both algorithms. C++ Module: lambertPlanner forwards the selection made with setTransferDirection. Existing callers retain prograde behavior; retrograde callers must select their intended direction explicitly. Polar geometry uses a deterministic short/long transfer convention that accounts for floating-point cancellation. Unknown direction values are validated as integers before enum conversion, so rejection does not depend on undefined enum behavior.

  • GitHub issue 1651: The Gooding method in C++ Module: lambertSolver could return the same multi-revolution transfer in both valid solution slots, losing the other orbit. The initial guesses now use consistent minimum-time data and corrected branch formulas. A safeguarded minimum-time search also prevents divergence for transfers close to a full revolution, which could produce nonfinite velocities marked valid. Both methods return the coalesced orbit in both slots at the minimum time, within floating-point roundoff. Users of older releases can select IZZO to avoid the reported Gooding duplicate-solution issue.

  • GitHub issue 1649: Linux wheel builds could fail on upstream source-download errors despite an available backup because the Conan configuration helper ignored CONAN_HOME and wrote settings to an unused cache. The helper now configures the selected cache, retaining TLS and source-checksum verification. Source-distribution release validation also runs this helper before installation, so an upstream download failure can use the same backup server as wheel builds.

  • GitHub issue 1644: The C ukfLUBckSlv() utility could return a wrong solution when the first nonzero entry of the pivoted right-hand side was below 1 in magnitude, because it cast that entry to int before testing it for zero. No module calls it, and ukfMatInv(), which back-solves unit vectors, was not affected.

  • GitHub issue 1646: The linearAlgebra utilities had correctness and memory-safety defects in rectangular matrix operations, overlapping-buffer use, comparisons, zero and empty inputs, matrix inverses, and root and spectral calculations. These are corrected while retaining the pure-C implementation and public API. Matrices near numerical singularity may now be rejected by inverse routines; see the API documentation for the numerical checks, supported dimensions, overlap rules, and remaining numerical limits.

  • GitHub issue 1638: With setUseApHistory(True), the C++ Module: msisAtmosphere module omitted the UT and longitude dependent magnetic activity term of NRLMSISE-00, because globe7() cast its coefficient to int before testing it for zero. The density and temperature errors grew with the 3-hour Ap and exceeded 20 % and 100 K at some locations at Ap 100. The default daily Ap mode was not affected.

  • Windows builds could abort Python when a directly wrapped C function raised BasiliskError, including invalid planet identifiers passed to pixelLineBiasUKFMeasModel. The MSVC exception settings now allow these errors to propagate through C calls to the Python exception handler.

  • macOS builds could retain the previous MuJoCo framework after a dependency upgrade, mixing new headers with the old library and failing to load the resulting binaries. Framework discovery now refreshes during configuration, so an existing build directory follows the selected MuJoCo package.

  • With MuJoCo 3.16, MJScene XML exports could silently produce no file when generated body sites or subsequent structural edits had not been compiled. XML export now compiles pending changes and reports write failures, including an invalid output path.

  • GitHub issue 1631: The spherical harmonics gravity model replaced the reference radius loaded from the coefficient file with radEquator of the gravity body when the body was initialized. When the two radii differ, every term of degree \(n\) was scaled by \((R_{body}/R_{file})^n\). Spherical harmonics body initialization also rejects an unset, nonpositive, or nonfinite mu so the field cannot use the file GM while gravity-gradient torque uses an invalid body GM. To use the file GM, set planet.mu = planet.spherHarm.muBody after loading the file and before initializing the simulation.

  • Importing svIntegrators could make shared DoubleVector and MultiArray inputs fail SWIG conversion depending on import and first-use order, including when gravity and MuJoCo tests ran together. The integrator bindings now use matching vector type declarations, preserving both shared vector objects and Python lists as inputs.

  • GitHub issue 1629 (orbital calculations): Fixed defects in convergence, orbital geometry, and numerical stability across the C and Python orbital utilities, including singular and degenerate orbits, mean/osculating conversions, and environmental helpers. Also corrected characteristic orbital energy in keplerianOrbit and related controller, ephemeris, and eclipse calculations.

  • GitHub issue 1629 (compatibility and validation): Existing methods, NumPy scalar outputs, and legacy orbital conventions remain supported without deprecation. Optional checked APIs provide explicit input validation. Element inputs now require inclinations in [0, pi] radians (0 to 180 degrees), and invalid or unsupported calculations may fail explicitly. See Orbital Motion Compatibility for detailed compatibility guidance and limitations.

  • GitHub issue 1618: C Module: celestialTwoBodyPoint mixed reference-frame angular-rate components with inertial-frame basis-vector derivatives when computing domega_RN_N. The resulting angular acceleration was incorrect for general reference motion, including the single-body fallback. The zero-valued geometric terms are now omitted; the reference attitude and angular rate are unchanged.

  • Builds with Vizard or optical navigation used Protobuf C++ 3.21.12, which is no longer supported upstream. They now use Protobuf 6.33.5, with OpenCV 4.14.0 for optical navigation. Source builds require Conan 2.4.0 or newer, and the generated visualization bindings require Python Protobuf 6.33.5 or newer. The Vizard message schema is unchanged. CMake now refreshes the Protobuf compiler path when dependencies change, preventing existing build directories from retaining an incompatible compiler.

  • GitHub issue 1621: tleHandling.frame_bias() applied the GCRS to mean J2000 frame bias rotations in the reverse order and with the wrong sign of \(\xi_0\). The TEME to J2000/ICRF conversion used by tleHandling and ommHandling therefore shifted TLE and OMM initial states by about 1.3 m in LEO.

  • GitHub issue 1619: The C++ Module: imuSensor module computed DVFramePlatform by rotating the whole TotalAccumDV_BN_B of C++ Module: spacecraft with the attitudes of the current and the previous IMU call. C++ Module: spacecraft builds this field by adding the delta v of each integration step in the body frame of that step, so every attitude change between two IMU calls turned the delta v accumulated since the start of the simulation into a spurious delta v.

  • C++ Module: imuSensor did not discard the state of the previous IMU call in Reset().

  • MJSite left the fields of stateOutMsg other than the position, velocity, attitude and angular rate of the site uninitialized.

  • C++ Module: spacecraft did not initialize nonConservativeAccelpntB_B and omegaDot_BN_B of scStateOutMsg. They held uninitialized values in the message written before the first integration step and, with pointMassTranslationalOnly, during the whole simulation. They are now zero until computed.

  • GitHub issue 1615: The C++ Module: eclipse module returned the occulted fraction \((b/a)^2\) of the solar disk instead of the visible fraction \(1 - (b/a)^2\) when the disk of the occulting body lies entirely inside the solar disk, where \(a\) and \(b\) are the apparent radii of the Sun and the body. The same formula in PlanetRadiationBase, used by C++ Module: albedo and C++ Module: earthRadiationModel, was also corrected, even though that case is not reached for patches on the planet surface.

  • GitHub issue 1612: The C++ Module: spiceInterface module computed the GPS time of spiceTimeOutMsg as the elapsed TDB time since the GPS epoch instead of atomic time. GPSSeconds was in error by a periodic term of a few milliseconds, and GPSWeek and GPSRollovers could be one week early at a week boundary. JulianDateCurrent was read from a SPICE Julian date string, which has at most seven decimals, and was therefore quantized to 1e-7 day. GPSSeconds overflowed a 32-bit integer after GPS week 3550, and a simulation start before the GPS epoch produced invalid GPS outputs. The corrected UTC Julian date preserves the SPICE convention of holding at the following midnight during an inserted leap second, avoiding backward jumps.

  • GitHub issues 1610 and 1611: Rigid-body kinematics conversions and composition now preserve identity, small rotations, half-turns, and Euler singularities; PRV rate maps use analytic limits at zero and angle wrapping handles multiple revolutions. Python and Numba retain sequence inputs and non-contiguous PRV arrays. Numba uses wrappers and overloads to avoid deprecated list reflection; see RigidBodyKinematicsNumba for compiled-call requirements and the public callable interface. Representation singularities and extreme floating-point magnitudes remain outside the numerical guarantees; see Numerical scope and representation limits.

  • GitHub issue 1609: keplerianOrbit returned incorrect eccentric and mean anomalies, lost the sign of the flight-path angle, and returned zero rates after construction or stale rates after set_a(). These outputs are now consistent with the current elliptic orbit. set_mu() now refreshes the derived state immediately, and oe().rmag reports the current radius instead of zero. Anomalies follow the orbitalMotion.f2E() and E2M() conventions without additional normalization to the interval from zero to two pi radians.

  • Optional wheel packaging could fail when independent runners supplied different Rust and Cargo versions. Nightly, release, and optional-wheel test workflows now resolve stable Rust once per run and use that exact toolchain for all core and opNav wheel builds, including builds inside Linux containers.

  • The C++ Module: stripLocation module held its target at the endpoint after completion but continued reporting motion at the acquisition speed. The target velocity relative to the planet-fixed frame is now zero at and after completion, keeping the strip state and access rate outputs consistent with the fixed endpoint.

  • The C++ Module: stripLocation module omitted rotation of the local SEZ frame as the target moved along a strip. Its v_BL_L, az_dot and el_dot outputs therefore disagreed with the derivatives of the published geometry for a moving target. These outputs now include the local-frame rotation; the range rate is unchanged.

  • The C++ Module: stripLocation module did not copy the computed SEZ relative velocity into the v_BL_L field of its access messages, which therefore always reported zero. The C++ Module: groundMapping module never assigned its planet-fixed to SEZ rotation matrix, so its r_BL_L, v_BL_L, azimuth and rate outputs were computed from an uninitialized matrix. C++ Module: groundMapping also crossed the planet angular velocity in planet-fixed components with inertial vectors, and did not subtract the planet velocity of planetInMsg, as described in the two entries below. The C++ Module: groundMapping module also did not populate the rHat_LP_N field of its ground state messages.

  • The C++ Module: groundLocation and C++ Module: groundMapping modules did not guard the division by the horizontal distance to the spacecraft in the azimuth, az_dot and el_dot access message fields, so these fields were undefined for a spacecraft exactly overhead of the location. The overhead test first used a fixed threshold of 1e-12 m on the horizontal distance, which is below the floating-point round-off of the SEZ position, so it could miss an exactly overhead spacecraft and leave azimuth dependent on round-off and az_dot and el_dot very large. The guard now accounts separately for distant-origin position quantization and local frame-transformation round-off, preserving resolvable near-overhead offsets in all three ground access modules.

  • GitHub issue 1606: The C++ Module: groundLocation and C++ Module: groundMapping modules did not subtract the planet velocity of planetInMsg from the spacecraft velocity, so the v_BL_L, range_dot, az_dot and el_dot access message fields were in error by the planet velocity.

  • GitHub issue 1605: The C++ Module: groundLocation, C++ Module: stripLocation and C++ Module: groundMapping modules crossed the planet angular velocity, which they computed in planet-fixed components, with inertial vectors when removing the planet rotation from the spacecraft velocity. The v_BL_L, range_dot, az_dot and el_dot access message fields were in error when the planet spin axis was not aligned with the inertial 3-axis.

  • The gravity effector advanced the planet orientation of a SPICE-driven planet with a first-order update of the matrix elements, which is not orthonormal and distorted even a point-mass field by a relative error of order \((\omega\,\Delta t)^2\). The orientation is now advanced as a rotation about the planet angular velocity.

  • The atmosphere, wind, magnetic field, eclipse, and solar flux modules evaluated the spacecraft state of the previous step, which made the solar radiation pressure shadow entries and exits a step late. The state can now be extrapolated to the middle of the step with setExtrapolateScStateToStepMidpoint(), which is disabled by default.

  • The C++ Module: msisAtmosphere module computed the altitude over a sphere and used the mean solar time. The altitude above an oblate planet is now available with setPlanetPolarRadius(), and the apparent solar time with setUseApparentSolarTime(). Both are disabled by default.

  • Atmosphere models that are evaluated once per integration step still show a step-size dependent drag error, which is second order in the step.

  • The C++ Module: msisAtmosphere, C++ Module: windBase, C++ Module: magneticFieldBase, and C++ Module: magneticFieldWMM modules converted the UTC epoch with mktime, which uses the time zone of the computer. On a computer in a time zone with daylight saving time, the local solar time was one hour wrong for the part of a simulation on the other side of a daylight saving transition than the epoch. The epoch is now converted as UTC.

  • The C++ Module: msisAtmosphere module used the daily Ap index and did not use the array of 3-hour Ap values that NRLMSISE-00 uses in its storm mode, so during a geomagnetic storm the density followed the daily mean from midnight. The 3-hour history is now available with setUseApHistory(), which is disabled by default.

  • The C++ Module: facetSRPDynamicEffector module used a solar flux of 1368 W/m2 at 1 AU, while C++ Module: radiationPressure uses 1361 W/m2. Both now use SOLAR_FLUX_EARTH.

  • GitHub issue 1598: Compilation database export requires Ninja or a Makefile generator; Xcode and Visual Studio do not support export. Clangd does not automatically discover the generated database in the default dist3 build directory. Configure clangd to use the directory containing compile_commands.json; see Configuring clangd for generator selection and the default and custom build-directory settings. Disabling export now removes an existing database from the selected build directory so clangd cannot keep reading stale compilation commands.

  • Visual Studio 2026 solution-wide clean could fail because the C-message target used an absolute path as its solution folder. It now uses a valid relative folder name.

  • Ninja Multi-Config builds could fail on C message interface dependencies. CMake now preserves these configured sources across native clean operations and avoids dependencies on other build configurations.

  • scenarioSmallBodyNav supplied an 18-element state to the 12-state smallBodyNavEKF, causing Debug builds to abort. The example now supplies 12 elements. Invalid state and matrix dimensions raise BasiliskError in Python during reset or update.

  • A buffer overflow in headingSuKF covariance updates and invalid zero-noise sampling in hingedRigidBodyMotorSensor are fixed. Both defects affected Debug and Release builds.

  • horizonOpNav could use incorrect or uninitialized planet radii. A zero limb-message planet ID now preserves planetTarget; a supported nonzero ID updates it before the calculation. Unsupported IDs raise BasiliskError.

  • On macOS, validating many native extensions could delay the first Basilisk import after a build. Message, core FSW, core simulation, MuJoCo, and OpenCV bindings now use fewer libraries to reduce this overhead. Python imports and recorder APIs are unchanged. Rebuilt libraries still require validation, so first imports can remain slower than subsequent runs.

  • GitHub issue 1587: The vscmg case in benchmarks/dynamics/benchmark_state_effectors.py failed during initialization with two or more components because of left-handed gimbal frames. The affected axes now form right-handed frames, fixing the benchmark in the current version.

  • Two-axis spinning-body default names could collide with single-axis state and property names once instance counters reached multiple digits. The two-axis names now separate the axis and instance numbers with _. Access these records through each effector’s public name fields.

  • Empty reaction-wheel and thruster effectors remain usable with flat-state registration. They do not create zero-sized state records, and their device counts still become immutable after successful registration.

  • Dynamics-manager references and callback-created state handles are borrowed. Keep the owning dynamics object or MuJoCo scene alive while using them. Replacing an integrator destroys the old method; reacquire the integrator property afterward. Python rejects reinstalling a previously transferred or borrowed integrator after replacement or owner destruction.

  • GitHub issue 1581: The C debyeLength() utility could read beyond its lookup arrays for altitudes from 2,000 km through 30,000 km, producing undefined results such as NaN. The interval search now includes the final table endpoint and returns the intended constant value of 0.0396 m throughout this range. NaN altitudes could also trigger an out-of-bounds read; they now produce an error diagnostic and return NaN before interpolation.

  • The deprecated Basilisk.simulation.spacecraftSystem module and its supporting effector APIs have been removed. Use C++ Module: spacecraft with C++ Module: constraintDynamicEffector for connected spacecraft; see scenarioConstrainedDynamics for a working example. API migration details are listed in the release notes. The supported prescribed-motion branches also no longer emit a missing-state warning when looking up an unused hub-attitude state during initialization.

  • GitHub issue 1563: BSpline.approximate() could ignore the second and third components of the final-acceleration constraint by reading uninitialized constraint-vector entries. All three components now use the correct constraint row. This is fixed in the current version.

  • GitHub issue 282: Passing the active integrator back to setIntegrator() could delete it and leave the dynamics object with a dangling pointer. The operation is now a no-op, and persistent integrator ownership uses std::unique_ptr. Python integrator attribute assignment now transfers ownership through the same setter. Explicitly disowning a newly constructed Python integrator before installation remains supported. Custom C++ dynamics classes should replace direct raw-pointer assignments to the owning member with setIntegrator(std::make_unique<IntegratorType>(this)) or transfer an existing unique_ptr with std::move; see Creating DynamicObject Basilisk Modules.

  • GitHub issue 282: Synchronized dynamics could retain a dangling pointer after a secondary was destroyed, or leave a surviving secondary marked as synchronized after its primary was destroyed. Python connections now retain their supplied secondary objects, and native destruction removes synchronization links in either order. Repeated connections are harmless; invalid self, nested, or competing-primary connections now raise BasiliskError. Python calls through borrowed primary proxies are rejected before changing connections; use the owning primary object so retention survives temporary aliases. See Lifetime of Synchronized Objects.

  • GitHub issue 282: Resetting simulation threads could clear process assignments while a worker was still using them, and shutdown requests used an unsynchronized flag. Worker ownership now guarantees stop and join before releasing thread state or changing assignments. requestStop() and the compatible killThread() now wake idle workers on the first stop request; repeated calls are harmless. Pool shutdown signals all workers before joining. See Reinitialization, ownership, and shutdown for configuration and C++ migration details.

  • GitHub issue 282: Dynamically allocated output messages now use private std::unique_ptr storage, preserving the public message-vector interfaces. This fixes missing cleanup in the two-axis spinning-body effector, joint controllers, thruster on-time converter, and the nested wheel/thruster outputs of DataFileToViz. Partially constructed output collections are also cleaned up when allocation fails. The shared addOwnedMessage() helper rolls back each owner/view insertion if either append fails; earlier module configuration changes are not rolled back. See Vector of Output Messages for the ownership and reconfiguration contract.

  • GitHub issue 282: Spacecraft-input configuration methods in the atmosphere, magnetic-field, wind, eclipse, location, charging, MSM, and formation-barycenter models could retain pointers to standalone Python messages after those messages were collected. These methods, along with Eclipse.addPlanetToModel() and EphemerisConverter.addSpiceInputMsg(), now retain each source through its native reader and release it on unsubscribe, replacement, or reader destruction. The same protection now covers power and data storage, transmitters, downlink handling, mapping instruments, simple-antenna and albedo planet inputs, articulated facets, thruster attached-body inputs, small-body navigation thruster inputs, and Vizard camera configuration messages. Pending and copied readers retain their sources until the last connected copy is released. Module-owned outputs still require their producing module to remain alive. See Retaining Sources in Configuration Methods.

  • GitHub issue 282: SPICE scratch buffers could leak when spacecraft-name validation or allocation raised an exception. Fixed-size arrays and an automatically managed time-output buffer now guarantee cleanup. The internal SpiceInterface.spiceBuffer and charBufferSize fields are now private; custom code must remove direct access to them. Standard simulation configuration is unchanged. Time-output formats that leave insufficient buffer capacity now raise BasiliskError before calling SPICE.

  • GitHub issue 282: Fuel tanks could keep dangling pointers to thruster effectors and fuel-slosh particles created in a local Python scope. addThrusterSet() and pushFuelSloshParticle() now retain their supplied Python objects until the tank is destroyed. Null connections, and dynamic-thruster connections made before setTankModel(), now raise BasiliskError. C++ callers must still keep borrowed effectors alive. See C++ Module: fuelTank.

  • GitHub issue 281: The C and C++ template documentation now explains the implemented calculation, optional inputs, reset behavior, and runnable usage. General RST authoring examples previously embedded in C Module: cModuleTemplate are now in Module RST Documentation.

  • GitHub issue 281: Draft module tests generated by makeDraftModule previously reported success without checking execution or outputs. Newly generated tests check scheduled call counts, output written status, and recording and write timestamps. Existing module tests must be updated manually; regenerating a draft replaces its folder.

  • GitHub issue 281: makeDraftModule could generate invalid test imports for nested paths or paths without a trailing separator, change the caller’s working directory, and delete an existing module before rejecting an invalid specification. Generation now normalizes paths, preserves the working directory, validates inputs, and stages complete drafts before replacement. Failures raise Python exceptions.

  • GitHub issue 281: The C and C++ module template fields dummy and dumVector are now named updateCounter and sampleConfigVector. Update Python assignments and logger field names accordingly. The C++ accessors are now setUpdateCounter(), getUpdateCounter(), setSampleConfigVector(), and getSampleConfigVector(); the old names are no longer available. Reset() still clears the counter and preserves the sample configuration vector, which is used for logging examples.

  • GitHub issue 1573: Rust input MsgReader ports exposed is_linked but not whether the subscribed source had been written, when it was written, or which module wrote it. Readers now provide is_written, time_written in nanoseconds, and module_id, following the subscribed source header. A linked message that has never been published reports unwritten, time zero, and an error for the module ID. Output writers do not expose these queries.

  • Incremental native builds could retain an old version in Basilisk.getBuildInfo() after docs/source/bskVersion.txt changed. CMake now tracks that file and reads the current source version instead of Conan’s cached version. Running ninja -j 12 in an existing build directory applies the fix and refreshes the metadata without a clean build.

  • C++ Module: spacecraftLocation formed its Sun direction from the inertial origin and its viewing direction from the primary spacecraft center instead of the configured body-fixed location. Illumination and viewing angles for translated or offset locations are corrected in the current version (issue #864). NaN glareThreshold values are now rejected during initialization rather than silently bypassing glare rejection.

  • GitHub issue 1393: The C++ Module: constraintDynamicEffector applied its constraint force and torque regardless of the device status message, which gated only the load filtering and the output message write. Commanding the effector off left its logged force at zero whereas the constraint kept acting on the dynamics. This is fixed in the current version.

  • Container release builds now free runner disk space and support recovery from an existing release tag without moving it.

  • In Basilisk 2.12.1, importing the support-data loader checks GitHub for a release tag even when local or cached files are available, adding network-dependent startup delays. The lookup is now deferred until a repository-hosted file needs downloading. Local files, valid cached files, and explicit external download URLs avoid the lookup; release-tag selection and the fallback to develop are preserved when a download is required.

  • In Basilisk 2.12.1, direct conanfile.py and CMake builds could accept Python versions outside the range declared in package metadata, even though package installation rejected them. Both build paths now enforce project.requires-python from pyproject.toml. For affected releases, create a virtual environment with a supported Python version before building and installing Basilisk.