std.http.Client.fetch uses .? that causes panic. Is this a known and reported bug or intentional for any reasons?

I currently got into this thing:

thread 1732993 panic: attempt to use null value

/home/qs/zig-x86_64-linux-0.17.0-dev.1415+64dfaa568/lib/std/http/Client.zig:1864:54: 0x126554e in fetch (std.zig)
error.ReadFailed => return response.bodyErr().?

I looked at the codes in Zig Documentation , and realized that there are multiple bodyErr().?

Shouldn’t this null need to be handled properly instead of crashing the program? If the program has its loop to wait and retry when the Internet is down, this won’t work because it may not have bodyErr.

Or did I misunderstand something?

Some digging and it looks like yes this is a bug.

bodyErr is only non-null when the error occurs within the body reader, but if the error occurred within the underlying stream/tls reader then it is still null.

2 Likes

The bug isn’t in the dereference. Whenever a reader implementation hits an error it’s supposed to set it’s error field(body_err in this case), then return the generic error.ReadFailed. The user’s should be able to retrieve the real error from there.
At least that’s the current pattern that’s used by writers/readers
There are a couple instances where that doesn’t appear to happen, but i’m not 100% that’s the problem.
1, 2

Do you have the full error trace?

thread 1732993 panic: attempt to use null value
error return context:
/home/qs/zig-x86_64-linux-0.17.0-dev.1415+64dfaa568/lib/std/Io/net.zig:1249:9: 0x138a4e7 in read (std.zig)
        return (try io.operate(.{ .net_read = .{
        ^
/home/qs/zig-x86_64-linux-0.17.0-dev.1415+64dfaa568/lib/std/Io/net.zig:1305:17: 0x1389eaf in readVec (std.zig)
                return error.ReadFailed;
                ^
/home/qs/zig-x86_64-linux-0.17.0-dev.1415+64dfaa568/lib/std/Io/Reader.zig:1139:9: 0x10b0e6b in fillMore (std.zig)
    _ = try r.vtable.readVec(r, &bufs);
        ^
/home/qs/zig-x86_64-linux-0.17.0-dev.1415+64dfaa568/lib/std/crypto/tls/Client.zig:1172:37: 0x138c4d5 in readIndirect (std.zig)
            error.ReadFailed => |e| return e,
                                    ^
/home/qs/zig-x86_64-linux-0.17.0-dev.1415+64dfaa568/lib/std/crypto/tls/Client.zig:1141:5: 0x138bb77 in readVec (std.zig)
    return readIndirect(c);
    ^
/home/qs/zig-x86_64-linux-0.17.0-dev.1415+64dfaa568/lib/std/Io/Reader.zig:1139:9: 0x10b0e6b in fillMore (std.zig)
    _ = try r.vtable.readVec(r, &bufs);
        ^
/home/qs/zig-x86_64-linux-0.17.0-dev.1415+64dfaa568/lib/std/http.zig:578:29: 0x1269f63 in chunkedReadEndless (std.zig)
                            try in.fillMore();
                            ^
/home/qs/zig-x86_64-linux-0.17.0-dev.1415+64dfaa568/lib/std/http.zig:546:56: 0x1268fce in chunkedStream (std.zig)
            error.ReadFailed, error.WriteFailed => |e| return e,
                                                       ^
/home/qs/zig-x86_64-linux-0.17.0-dev.1415+64dfaa568/lib/std/Io/Reader.zig:466:21: 0x1064cca in defaultReadVec (std.zig)
        else => |e| return e,
                    ^
/home/qs/zig-x86_64-linux-0.17.0-dev.1415+64dfaa568/lib/std/Io/Reader.zig:1128:36: 0x1063747 in fillUnbuffered (std.zig)
    while (r.end < r.seek + n) _ = try r.vtable.readVec(r, &bufs);
                                   ^
/home/qs/zig-x86_64-linux-0.17.0-dev.1415+64dfaa568/lib/std/Io/Reader.zig:1114:5: 0x1063478 in fill (std.zig)
    return fillUnbuffered(r, n);
    ^
/home/qs/zig-x86_64-linux-0.17.0-dev.1415+64dfaa568/lib/std/Io/Reader.zig:515:5: 0x10b11d3 in peek (std.zig)
    try r.fill(n);
    ^
/home/qs/zig-x86_64-linux-0.17.0-dev.1415+64dfaa568/lib/std/Io/Reader.zig:596:13: 0x16e693c in peekArray__anon_398123 (std.zig)
    return (try r.peek(n))[0..n];
            ^
/home/qs/zig-x86_64-linux-0.17.0-dev.1415+64dfaa568/lib/std/Io/Reader.zig:1181:31: 0x16d9615 in peekInt (std.zig)
    return std.mem.readInt(T, try r.peekArray(n), endian);
                              ^
/home/qs/zig-x86_64-linux-0.17.0-dev.1415+64dfaa568/lib/std/compress/flate/Decompress.zig:527:58: 0x16d9729 in peekBits (std.zig)
    const bits = d.input.peekInt(u32, .little) catch |e| return switch (e) {
                                                         ^
/home/qs/zig-x86_64-linux-0.17.0-dev.1415+64dfaa568/lib/std/compress/flate/Decompress.zig:552:18: 0x16d9997 in takeBits (std.zig)
    const bits = try d.peekBits(n);
                 ^
/home/qs/zig-x86_64-linux-0.17.0-dev.1415+64dfaa568/lib/std/compress/flate/Decompress.zig:586:21: 0x16d9abd in takeIntBits__anon_398105 (std.zig)
    return @intCast(try d.takeBits(@bitSizeOf(T)));
                    ^
/home/qs/zig-x86_64-linux-0.17.0-dev.1415+64dfaa568/lib/std/compress/flate/Decompress.zig:318:30: 0x16e1a27 in streamInner (std.zig)
            d.final_block = (try d.takeIntBits(u1)) != 0;
                             ^
/home/qs/zig-x86_64-linux-0.17.0-dev.1415+64dfaa568/lib/std/compress/flate/Decompress.zig:265:13: 0x16d8d93 in streamFallible (std.zig)
            return error.ReadFailed;
            ^
/home/qs/zig-x86_64-linux-0.17.0-dev.1415+64dfaa568/lib/std/compress/flate/Decompress.zig:178:21: 0x16d8715 in streamIndirectInner (std.zig)
        else => |e| return e,
                    ^
/home/qs/zig-x86_64-linux-0.17.0-dev.1415+64dfaa568/lib/std/compress/flate/Decompress.zig:247:5: 0x16d8447 in streamIndirect (std.zig)
    return streamIndirectInner(d);
    ^
/home/qs/zig-x86_64-linux-0.17.0-dev.1415+64dfaa568/lib/std/Io/Reader.zig:176:15: 0x1065cf3 in stream (std.zig)
    const n = try r.vtable.stream(r, w, limit);
              ^
/home/qs/zig-x86_64-linux-0.17.0-dev.1415+64dfaa568/lib/std/Io/Reader.zig:267:25: 0x111ad44 in streamRemaining (std.zig)
            else => |e| return e,
                        ^

stack trace:
/home/qs/zig-x86_64-linux-0.17.0-dev.1415+64dfaa568/lib/std/http/Client.zig:1864:54: 0x126554e in fetch (std.zig)
        error.ReadFailed => return response.bodyErr().?,
                                                     ^
/home/qs/mycodes/myhttp.zig:119:47: 0x1216728 in products (main.zig)
        const response = try self.client.fetch(.{

Vulpesx is correct then. It looks like the bodyReader needs to reach into it’s nested Reader to pull out it’s err field, but that doesn’t seem like a simple task. Definitely a bug tho

1 Like