stride3d/stride · error · ArgumentException

Pointer to DDS header cannot be null

Error message

Pointer to DDS header cannot be null

What it means

DecodeDDSHeader validates the incoming pointer to a DDS header before parsing. A null/IntPtr.Zero pointer cannot contain a header, so it immediately throws ArgumentException naming the headerPtr parameter, mirroring DirectXTex's behavior.

Solutions

  1. Ensure the buffer containing DDS data is loaded and non-empty before decoding
  2. Check any pointer-producing call (AllocGCHandle, Alloc, native alloc) for failure and handle IntPtr.Zero before calling
  3. Fix the data-loading path so the DDS bytes are actually read into memory

Example fix

// before
if (dataPtr == IntPtr.Zero) { /* unchecked */ }
DecodeDDS(dataPtr, size, ...);
// after
if (dataPtr == IntPtr.Zero) throw new InvalidOperationException("DDS data not loaded");
DecodeDDS(dataPtr, size, ...);
Defensive patterns

Strategy: validation

Validate before calling

if (headerPtr == IntPtr.Zero)
    throw new InvalidOperationException("DDS data buffer was not loaded; cannot decode header");
if (size < 4 + sizeof(DDS.Header))
    throw new InvalidOperationException("DDS buffer too small to contain a header");

Try / catch

try { ok = DecodeDDSHeader(ptr, size, flags, out desc, out conv); } catch (ArgumentException ex) when (ex.ParamName == "headerPtr") { // fix data loading before retry
    throw new InvalidOperationException("DDS source pointer was null; load the file bytes first", ex); }

Prevention

When it happens

Trigger: Calling DDS loading/decoding APIs (Image.Load / DDS decoding path) with IntPtr.Zero as the header pointer, typically from a failed buffer pin/allocation, passing an uninitialized pointer, or a null byte[] marshaled to pointer.

Common situations: P/Invoke or unsafe interop returning IntPtr.Zero on failure that is then passed to the DDS decoder, loading from a stream/buffer where the data pointer was never set, custom native integrations.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/856feab575f54c2f. Report an issue: GitHub.

Appendix: source

Thrown at sources/engine/Stride.Foundation/Graphics/DDSHelper.cs:299

        /// <summary>
        /// Decodes DDS header including optional DX10 extended header
        /// </summary>
        /// <param name="headerPtr">Pointer to the DDS header.</param>
        /// <param name="size">Size of the DDS content.</param>
        /// <param name="flags">Flags used for decoding the DDS header.</param>
        /// <param name="description">Output texture description.</param>
        /// <param name="convFlags">Output conversion flags.</param>
        /// <exception cref="ArgumentException">If the argument headerPtr is null</exception>
        /// <exception cref="InvalidOperationException">If the DDS header contains invalid datas.</exception>
        /// <returns>True if the decoding is successfull, false if this is not a DDS header.</returns>
        private static unsafe bool DecodeDDSHeader(IntPtr headerPtr, int size, DDSFlags flags, out ImageDescription description, out ConversionFlags convFlags)
        {
            description = new ImageDescription();
            convFlags = ConversionFlags.None;

            if (headerPtr == IntPtr.Zero)
                throw new ArgumentException("Pointer to DDS header cannot be null", "headerPtr");

            if (size < (Unsafe.SizeOf<DDS.Header>() + sizeof (uint)))
                return false;

            // DDS files always start with the same magic number ("DDS ")
            if (*(uint*) (headerPtr) != DDS.MagicHeader)
                return false;

            var header = *(DDS.Header*) ((byte*) headerPtr + sizeof (int));

            // Verify header to validate DDS file
            if (header.Size != Unsafe.SizeOf<DDS.Header>() || header.PixelFormat.Size != Unsafe.SizeOf<DDS.DDSPixelFormat>())
                return false;

            // Setup MipLevels
            description.MipLevels = header.MipMapCount;
            if (description.MipLevels == 0)
                description.MipLevels = 1;

View on GitHub (pinned to 96fad776d2)