LykosAI/StabilityMatrix · error · InvalidDataException

JSON does not start with '{'.

Error message

JSON does not start with '{'.

What it means

ParseAsync throws this when byte 8 of the safetensors file (the first byte of the JSON header) is not '{'. The 8-byte length prefix must be immediately followed by the opening brace of the JSON header.

Solutions

  1. Verify the file is a genuine safetensors file (magic: 8-byte little-endian length then '{').
  2. Reset the stream position to 0 before calling ParseAsync.
  3. Re-download or re-convert the model file.
  4. Add a pre-check that reads the first 9 bytes and validates the pattern.

Example fix

// before
var meta = await SafetensorMetadata.ParseAsync(fileStream);
// after
fileStream.Position = 0;
var probe = new byte[9];
await fileStream.ReadExactlyAsync(probe);
if (probe[8] != (byte)'{') throw new InvalidDataException("Not a safetensors file.");
fileStream.Position = 0;
var meta = await SafetensorMetadata.ParseAsync(fileStream);
Defensive patterns

Strategy: validation

Validate before calling

using var fs = File.OpenRead(path);
var probe = new byte[9];
if (await fs.ReadAsync(probe) < 9 || probe[8] != (byte)'{')
    throw new InvalidDataException("File does not look like safetensors.");
fs.Position = 0;

Type guard

bool LooksLikeSafetensors(byte[] first9) => first9.Length >= 9 && first9[8] == (byte)'{';

Try / catch

try { var meta = await SafetensorMetadata.ParseAsync(stream); }
catch (InvalidDataException ex)
{
    _logger.LogError(ex, "Not a valid safetensors file");
    notificationService.ShowPersistentDialog("Invalid file", ex.Message);
}

Prevention

When it happens

Trigger: Reading a file whose byte at offset 8 is not '{': non-safetensors files, wrong stream position, headers whose length prefix is misinterpreted.

Common situations: Renamed model files (ckpt/gguf named .safetensors), partially written files, reading from a stream that was already partially consumed.

Understand the failure class

Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.

Related errors


AI-assisted analysis of LykosAI/StabilityMatrix@af93d6ef57 (2026-09-12). Data as JSON: /api/errors/6ccabdec32c887e5. Report an issue: GitHub.

Appendix: source

Thrown at StabilityMatrix.Core/Models/SafetensorMetadata.cs:48

    /// <param name="safetensorStream">Stream to the SafeTensor file.</param>
    /// <returns>The parsed metadata. Can be <see langword="null"/> if the file does not contain metadata.</returns>
    public static async Task<SafetensorMetadata?> ParseAsync(Stream safetensorStream)
    {
        // 8 bytes unsigned little-endian 64-bit integer
        // 1 byte start of JSON object '{'
        Memory<byte> buffer = new byte[9];
        await safetensorStream.ReadExactlyAsync(buffer).ConfigureAwait(false);
        var span = buffer.Span;

        const ulong MAX_ALLOWED_JSON_LENGTH = 100 * 1024 * 1024; // 100 MB
        var jsonLength = BinaryPrimitives.ReadUInt64LittleEndian(span);
        if (jsonLength > MAX_ALLOWED_JSON_LENGTH)
        {
            throw new InvalidDataException("JSON length exceeds the maximum allowed size.");
        }
        if (span[8] != '{')
        {
            throw new InvalidDataException("JSON does not start with '{'.");
        }

        // Unfornately Utf8JsonReader does not support reading from a stream directly.
        // Usually the size of the entire JSON object is less than 500KB,
        // using a pooled buffer should reduce the number of large allocations.
        var jsonBytes = ArrayPool<byte>.Shared.Rent((int)jsonLength);
        try
        {
            // Important: the length of the rented buffer can be larger than jsonLength
            // and there can be additional junk data at the end.

            // we already read {, so start from index 1
            jsonBytes[0] = (byte)'{';
            await safetensorStream
                .ReadExactlyAsync(jsonBytes, 1, (int)(jsonLength - 1))
                .ConfigureAwait(false);

            // read the JSON with Utf8JsonReader, then only deserialize what we need

View on GitHub (pinned to af93d6ef57)