diff --git a/src/semantic.zig b/src/semantic.zig index ac1c63b6..12d75977 100644 --- a/src/semantic.zig +++ b/src/semantic.zig @@ -344,11 +344,12 @@ fn fetchHttpResponseOnce( .response_writer = &response_writer, }); if (fetch_result.status != .ok) { - return switch (fetch_result.status) { - .too_many_requests => error.EmbeddingRateLimited, - .internal_server_error, .bad_gateway, .service_unavailable, .gateway_timeout => error.EmbeddingProviderUnavailable, - else => error.EmbeddingProviderRejected, - }; + if (fetch_result.status == .too_many_requests) return error.EmbeddingRateLimited; + // Gateways can emit non-standard 5xx codes that the status enum does + // not name. They are still provider failures, not client rejections. + const status_code = @intFromEnum(fetch_result.status); + if (status_code >= 500 and status_code < 600) return error.EmbeddingProviderUnavailable; + return error.EmbeddingProviderRejected; } return try allocator.dupe(u8, response_writer.buffer[0..response_writer.end]); } diff --git a/src/test_semantic.zig b/src/test_semantic.zig index 041195b2..c2098cfd 100644 --- a/src/test_semantic.zig +++ b/src/test_semantic.zig @@ -516,8 +516,10 @@ test "semantic: provider 4xx and 5xx responses fail closed with retryable classe defer guards.deinit(); for ([_]struct { status: []const u8, expected: anyerror }{ + .{ .status = "403 Forbidden", .expected = error.EmbeddingProviderRejected }, .{ .status = "429 Too Many Requests", .expected = error.EmbeddingRateLimited }, .{ .status = "500 Internal Server Error", .expected = error.EmbeddingProviderUnavailable }, + .{ .status = "530 Unknown Server Error", .expected = error.EmbeddingProviderUnavailable }, }) |case| { const addr = try std.Io.net.IpAddress.parse("127.0.0.1", 0); var server = try addr.listen(io, .{ .reuse_address = true, .mode = .stream, .protocol = .tcp });