ronantakizawa/codereview-bench huggingface dataset:
Repository: Orange-OpenSource/hurl
File: packages/hurl/src/http/response_ip.rs (Rust)

Code before:
/*
 * Hurl (https://hurl.dev)
 * Copyright (C) 2025 Orange
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *          http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
use std::str::FromStr;

#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct IpAddr {
    pub(crate) raw: String,
}

impl IpAddr {
    #[allow(dead_code)]
    fn to_ip_addr(&self) -> Result<std::net::IpAddr, String> {
        std::net::IpAddr::from_str(&self.raw)
            .map_err(|_| "Failed to parse IP address from response".to_string())
    }
}


Review comment (suggestion):
Here we don't want someone to have direct access to the `inner` field. 
Instead of `pub(crate) raw: String,`we want `raw: String,`.

The data is encapsulated inside the `IpAddr` and code using `IpAddr` instances doesn't have access to these private fields. If we need, for instance, an access to the `inner` value, we can add methods on `IpAddr`. In this case, we could implement `fmt::Display`so we can call `to_string` on this structure to get the value backed by `inner` field.

Code after:
/*
 * Hurl (https://hurl.dev)
 * Copyright (C) 2025 Orange
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *          http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
use std::fmt::{Display, Formatter};
use std::net::AddrParseError;
use std::str::FromStr;

/// An IP address, either IPv4 or IPv6.
///
/// The `raw` field of this structure comes from libcurl `as is`. We keep it as a
/// [`String`] instead of a [`std::net::IpAddr`] to not make any assumptions
/// of the address format. We don't want to invalidate an HTTP exchange and raise a
/// runtime error because of an unusual format coming from libcurl.
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct IpAddr {
    raw: String,
}

impl IpAddr {
    pub fn new(raw: String) -> IpAddr {
        IpAddr { raw }
    }
    #[allow(dead_code)]
    fn to_ip_addr(&self) -> Result<std::net::IpAddr, AddrParseError> {
        std::net::IpAddr::from_str(&self.raw)
    }
}

impl Display for IpAddr {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.raw)
    }
}
Repository: Orange-OpenSource/hurl
File: packages/hurl/src/http/response_ip.rs (Rust)

Code before:
 * Hurl (https://hurl.dev)
 * Copyright (C) 2025 Orange
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *          http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
use std::str::FromStr;

#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct IpAddr {
    pub(crate) raw: String,
}

impl IpAddr {
    #[allow(dead_code)]
    fn to_ip_addr(&self) -> Result<std::net::IpAddr, String> {
        std::net::IpAddr::from_str(&self.raw)
            .map_err(|_| "Failed to parse IP address from response".to_string())
    }
}


Review comment (suggestion):
If possible, we can reuse [AddrParseError](https://doc.rust-lang.org/beta/core/net/struct.AddrParseError.html) as the error

```rust
fn to_ip_addr(&self) -> Result<std::net::IpAddr, AddrParseError>
```



Code after:
 * Hurl (https://hurl.dev)
 * Copyright (C) 2025 Orange
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *          http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
use std::fmt::{Display, Formatter};
use std::net::AddrParseError;
use std::str::FromStr;

/// An IP address, either IPv4 or IPv6.
///
/// The `raw` field of this structure comes from libcurl `as is`. We keep it as a
/// [`String`] instead of a [`std::net::IpAddr`] to not make any assumptions
/// of the address format. We don't want to invalidate an HTTP exchange and raise a
/// runtime error because of an unusual format coming from libcurl.
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct IpAddr {
    raw: String,
}

impl IpAddr {
    pub fn new(raw: String) -> IpAddr {
        IpAddr { raw }
    }
    #[allow(dead_code)]
    fn to_ip_addr(&self) -> Result<std::net::IpAddr, AddrParseError> {
        std::net::IpAddr::from_str(&self.raw)
    }
}

impl Display for IpAddr {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.raw)
    }
}
Repository: Orange-OpenSource/hurl
File: packages/hurl/src/http/mod.rs (Rust)

Code before:
#[cfg(test)]
pub use self::tests::*;
pub use self::timings::Timings;
pub use self::url::Url;
pub use self::version::libcurl_version_info;

mod call;
mod certificate;
mod client;
mod cookie;
mod core;
mod curl_cmd;
mod debug;
mod easy_ext;
mod error;
mod header;
mod headers_helper;
mod mimetype;
mod options;
mod request;
mod request_spec;
mod response;
mod response_cookie;
mod response_debug;
mod response_decoding;
mod ip;
#[cfg(test)]
mod tests;
mod timings;
mod timings_debug;
mod url;
mod version;


Review comment (suggestion):
`mod ip` could be up a few lines so all the mod are sorted. You can reformat the code with `cargo fmt` and the CI/CD will be appeased.

Code after:
#[cfg(test)]
pub use self::tests::*;
pub use self::timings::Timings;
pub use self::url::Url;
pub use self::version::libcurl_version_info;

mod call;
mod certificate;
mod client;
mod cookie;
mod core;
mod curl_cmd;
mod debug;
mod easy_ext;
mod error;
mod header;
mod headers_helper;
mod ip;
mod mimetype;
mod options;
mod request;
mod request_spec;
mod response;
mod response_cookie;
mod response_debug;
mod response_decoding;
#[cfg(test)]
mod tests;
mod timings;
mod timings_debug;
mod url;
mod version;
Repository: Orange-OpenSource/hurl
File: packages/hurl/src/runner/predicate.rs (Rust)

Code before:
        Err(_) => {
            return Err(RunnerError::new(
                source_info,
                RunnerErrorKind::InvalidIpAddr { value: ip },
                false,
            ))
        }
    };

    Ok(AssertResult {
        success: parsed.is_ipv4(),
        actual: actual.repr(),
        expected: "ipv4".to_string(),
        type_mismatch: false,
    })
}

/// Evaluates if an `actual` value is an IPv6 address.
fn eval_is_ipv6(source_info: SourceInfo, actual: &Value) -> Result<AssertResult, RunnerError> {
    let ip = actual.to_string();
    let parsed = match IpAddr::from_str(&ip) {
        Ok(ip) => ip,
        Err(_) => {
            return Err(RunnerError::new(
                source_info,
                RunnerErrorKind::InvalidIpAddr { value: ip },
                false,
            ))
        }
    };

    Ok(AssertResult {
        success: parsed.is_ipv6(),
        actual: actual.repr(),
        expected: "ipv6".to_string(),
        type_mismatch: false,
    })
}

fn assert_values_equal(actual: &Value, expected: &Value) -> AssertResult {
    let success = actual == expected;
    let actual = actual.repr();
    let expected = expected.repr();
    let type_mismatch = false;
    AssertResult {
        success,
        actual,
        expected,
        type_mismatch,
    }
}

Review comment (suggestion):
I think we can avoid creating the variant `InvalidIpAddr`. If a value is not parsable to an IP address, evaluating `isIpv6` on it should return `false` and not raise an error:

```
"Toto" isIpv6 == false
```


Code after:
            actual: actual.to_string(),
            expected: "string in IPv4 format".to_string(),
            type_mismatch: false,
        }),
        _ => Ok(AssertResult {
            success: false,
            actual: actual.repr(),
            expected: "string".to_string(),
            type_mismatch: true,
        }),
    }
}

/// Evaluates if an `actual` value is an IPv6 address.
fn eval_is_ipv6(actual: &Value) -> Result<AssertResult, RunnerError> {
    match actual.is_ipv6() {
        Ok(success) => Ok(AssertResult {
            success,
            actual: actual.to_string(),
            expected: "string in IPv6 format".to_string(),
            type_mismatch: false,
        }),
        _ => Ok(AssertResult {
            success: false,
            actual: actual.repr(),
            expected: "string".to_string(),
            type_mismatch: true,
        }),
    }
}

fn assert_values_equal(actual: &Value, expected: &Value) -> AssertResult {
    let success = actual == expected;
    let actual = actual.repr();
    let expected = expected.repr();
    let type_mismatch = false;
    AssertResult {
        success,
        actual,
        expected,
        type_mismatch,
    }
}

fn assert_values_not_equal(actual: &Value, expected: &Value) -> AssertResult {
    let success = actual != expected;
    let actual = actual.repr();
    let expected = expected.repr();
    let type_mismatch = false;
    AssertResult {
        success,
Repository: Orange-OpenSource/hurl
File: packages/hurl/src/runner/http_response.rs (Rust)

Code before:
use std::fmt::Display;

/// Represents an HTTP request for `Value::HttpResponse`
#[derive(Clone, Debug)]
pub struct HttpResponse {
    url: Url,
    status: u32,
}

impl HttpResponse {
    pub fn new(url: Url, status: u32) -> Self {
        HttpResponse { url, status }
    }

    pub fn url(&self) -> &Url {
        &self.url
    }

    pub fn status(&self) -> u32 {
        self.status
    }
}

impl Display for HttpResponse {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{:?}", self)
    }
}


Review comment (bug):
`{:?}`should be used to implement `fmt::Debug` not `fmt::Display`... We could simply write here:

```rust
write!(f, "url={} status={}", self.url, self.status)
```

Code after:
use std::fmt::Display;

/// Represents an HTTP request for `Value::HttpResponse`
#[derive(Clone, Debug)]
pub struct HttpResponse {
    /// URL of the request that triggers this response
    url: Url,
    /// Status code of the HTTP response
    status: u32,
}

impl HttpResponse {
    /// Returns a new HTTP response, given an `url` and a `status` code.
    pub fn new(url: Url, status: u32) -> Self {
        HttpResponse { url, status }
    }

    /// Returns the URL of the HTTP request associated to this response.
    pub fn url(&self) -> &Url {
        &self.url
    }

    /// Returns the HTTP status code of this response.
    pub fn status(&self) -> u32 {
        self.status
    }
}

impl Display for HttpResponse {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "url={} status={}", self.url, self.status)
    }
}
Repository: Orange-OpenSource/hurl
File: packages/hurl/src/runner/value.rs (Rust)

Code before:
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
use std::cmp::Ordering;
use std::fmt;

use crate::runner::HttpResponse;
use crate::runner::Number;

/// System types used in Hurl.
///
/// Values are used by queries, captures, asserts and predicates.
#[derive(Clone, Debug)]
pub enum Value {
    /// A boolean value.
    Bool(bool),
    /// A buffer of bytes.
    Bytes(Vec<u8>),
    /// A date.
    Date(chrono::DateTime<chrono::Utc>),
    /// A structure to represent an HTTP redirection.
    HttpResponse(HttpResponse),
    /// A list of [`Value`].
    List(Vec<Value>),
    /// A structure to represents node of object (returned from XPath queries).
    Nodeset(usize),
    /// The null type.
    Null,
    /// A number, can be a float, a 64-bit integer or any precision integer.
    Number(Number),
    /// A structure to represents objects (returned from JSONPath queries).
    Object(Vec<(String, Value)>),
    /// A regular expression.
    Regex(regex::Regex),
    /// A string.
    String(String),
    /// The unit type.
    Unit,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ValueKind {
    Bool,
    Bytes,
    Date,
    Float,

Review comment (suggestion):
We could use this structure for other scenarios so the comment should be:

```rust
/// A structure to represent an HTTP response.
```

Code after:
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
use std::cmp::Ordering;
use std::fmt;

use crate::runner::HttpResponse;
use crate::runner::Number;

/// System types used in Hurl.
///
/// Values are used by queries, captures, asserts and predicates.
#[derive(Clone, Debug)]
pub enum Value {
    /// A boolean value.
    Bool(bool),
    /// A buffer of bytes.
    Bytes(Vec<u8>),
    /// A date.
    Date(chrono::DateTime<chrono::Utc>),
    /// A structure to represent an HTTP response.
    HttpResponse(HttpResponse),
    /// A list of [`Value`].
    List(Vec<Value>),
    /// A structure to represents node of object (returned from XPath queries).
    Nodeset(usize),
    /// The null type.
    Null,
    /// A number, can be a float, a 64-bit integer or any precision integer.
    Number(Number),
    /// A structure to represents objects (returned from JSONPath queries).
    Object(Vec<(String, Value)>),
    /// A regular expression.
    Regex(regex::Regex),
    /// A string.
    String(String),
    /// The unit type.
    Unit,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ValueKind {
    Bool,
    Bytes,
    Date,
    Float,
Repository: Orange-OpenSource/hurl
File: packages/hurl/src/runner/http_response.rs (Rust)

Code before:
 * You may obtain a copy of the License at
 *
 *          http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
use crate::http::Url;
use std::fmt::Display;

/// Represents an HTTP request for `Value::HttpResponse`
#[derive(Clone, Debug)]
pub struct HttpResponse {
    /// URL of the request that triggers this response
    url: Url,
    /// Status code of the HTTP response
    status: u32,
}

impl HttpResponse {
    pub fn new(url: Url, status: u32) -> Self {
        HttpResponse { url, status }
    }

    pub fn url(&self) -> &Url {
        &self.url
    }

    pub fn status(&self) -> u32 {
        self.status
    }
}

impl Display for HttpResponse {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "url={} status={}", self.url, self.status)
    }
}


Review comment (suggestion):
Even if it's trivial, we should add some doc functions here:

```rust
/// Returns a new HTTP response, given an `url` and a `status` code.
pub fn new(url: Url, status: u32) -> Self {
}

/// Returns the URL of the HTTP request associated to this response.
pub fn url(&self) -> &Url {
}

/// Returns the HTTP status code of this response.
pub fn status(&self) -> u32 {
}
```


Code after:
 * You may obtain a copy of the License at
 *
 *          http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
use crate::http::Url;
use std::fmt::Display;

/// Represents an HTTP request for `Value::HttpResponse`
#[derive(Clone, Debug)]
pub struct HttpResponse {
    /// URL of the request that triggers this response
    url: Url,
    /// Status code of the HTTP response
    status: u32,
}

impl HttpResponse {
    /// Returns a new HTTP response, given an `url` and a `status` code.
    pub fn new(url: Url, status: u32) -> Self {
        HttpResponse { url, status }
    }

    /// Returns the URL of the HTTP request associated to this response.
    pub fn url(&self) -> &Url {
        &self.url
    }

    /// Returns the HTTP status code of this response.
    pub fn status(&self) -> u32 {
        self.status
    }
}

impl Display for HttpResponse {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "url={} status={}", self.url, self.status)
    }
}
Repository: Orange-OpenSource/hurl
File: integration/hurl/tests_failed/filter.py (Python)

Code before:
from app import app
from flask import Response


@app.route("/error-filter")
def error_filter():
    return Response(
        """{
          "file":"5L2g5aW95LiW5",
          "file_pad":"0YjQtdC70LvRiw==",
          "id":"123x",
          "status": true,
          "list": [1,2,3],
          "number": 42
}
""",
        mimetype="application/json",
    )


Review comment (suggestion):
Instead of this value `file_pad`, I would prefer having a value `text_encoded`: `PDw_Pz8-Pg`in response  that shows characters specific to base64 url safe encoding so the asserts could be:

```
jsonpath "$.text_encoded" == "PDw_Pz8-Pg"
jsonpath "$.text_encoded" base64UrlSafeDecode == "<<???>>"
jsonpath "$.text_encoded" base64UrlSafeDecode base64UrlSafeEncode == "PDw_Pz8-Pg"
jsonpath "$.text_encoded" base64UrlSafeDecode base64Encode == "PDw/Pz8+Pg=="
```


Code after:
from app import app
from flask import Response


@app.route("/error-filter")
def error_filter():
    return Response(
        """{
          "file":"5L2g5aW95LiW5",
          "text_encoded":"PDw_Pz8-Pg",
          "id":"123x",
          "status": true,
          "list": [1,2,3],
          "number": 42
}
""",
        mimetype="application/json",
    )
Repository: Orange-OpenSource/hurl
File: integration/hurl/tests_ok/secret/secret.sh (Shell)

Code before:
#!/bin/bash
set -Eeuo pipefail

rm -rf build/secret

hurl --very-verbose \
    --secrets-file tests_ok/secret/secrets0.env \
    --secrets-file tests_ok/secret/secrets1.env \
    --secret c=12345678 \
    --curl build/secret/curl.txt \
    --cookie-jar build/secret-cookies.txt \
    --report-html build/secret/report-html \
    --report-json build/secret/report-json \
    tests_ok/secret/secret.hurl

secrets=("secret1" "secret2" "secret3" "12345678" "secret-dynamic-0" "secret-dynamic-1" "secret-dynamic-2")

files=$(find build/secret/report-html/*.html \
  build/secret/report-html/**/*.html \
  build/secret/report-json/*.json \
  build/secret/curl.txt \
  build/secret-cookies.txt \
  tests_ok/secret/secret.err.pattern
)

for secret in "${secrets[@]}"; do
  for file in $files; do
    # Don't search leaks in sources
    if [[ "$file" == *source.html ]]; then
      continue
    fi
    if grep -q "$secret" "$file"; then

Review comment (security):
This integration file should not be touched, we can make a new integration test specifi for `--secrets-file` in `tests_ok/secret/secrets_file.sh`

Code after:
#!/bin/bash
set -Eeuo pipefail

rm -rf build/secret

hurl --very-verbose \
    --secret a=secret1 \
    --secret b=secret2 \
    --secret c=12345678 \
    --curl build/secret/curl.txt \
    --cookie-jar build/secret-cookies.txt \
    --report-html build/secret/report-html \
    --report-json build/secret/report-json \
    tests_ok/secret/secret.hurl

secrets=("secret1" "secret2" "secret3" "12345678" "secret-dynamic-0" "secret-dynamic-1" "secret-dynamic-2")

files=$(find build/secret/report-html/*.html \
  build/secret/report-html/**/*.html \
  build/secret/report-json/*.json \
  build/secret/curl.txt \
  build/secret-cookies.txt \
  tests_ok/secret/secret.err.pattern
)

for secret in "${secrets[@]}"; do
  for file in $files; do
    # Don't search leaks in sources
    if [[ "$file" == *source.html ]]; then
      continue
    fi
    if grep -q "$secret" "$file"; then
Repository: PathOfBuildingCommunity/PathOfBuilding
File: src/Classes/ImportTab.lua (Lua)

Code before:
	local largestGroupSize = 0
	local largestGroupIndex = 1
	for i, socketGroup in ipairs(self.build.skillsTab.socketGroupList) do
		if #socketGroup.gemList > largestGroupSize then
			largestGroupSize = #socketGroup.gemList
			largestGroupIndex = i
		end
	end
	return largestGroupIndex
end

function HexToChar(x)
	return string.char(tonumber(x, 16))
end

function ReplaceDiscrimintorSafely(accountName)
	reversedAccountName = string.reverse(accountName)
	discriminatorIndex = 0
	for i = 1, #reversedAccountName do
		local c = reversedAccountName:sub(i,i)
			if c == "#" or c == "-" then
			discriminatorIndex = i
			break
			end
	end
	discriminatorIndex = discriminatorIndex * -1
	return ReplaceCharAtIndex(accountName, discriminatorIndex, "#")
end

function UrlDecode(url)
	if url == nil then
		return
	end
	url = url:gsub("+", " ")
	url = url:gsub("%%(%x%x)", HexToChar)
	return url
end

function ImportTabClass:ProcessJSON(json)
	local func, errMsg = loadstring("return "..jsonToLua(json))
	if errMsg then
		return nil, errMsg
	end
	setfenv(func, { }) -- Sandbox the function just in case
	local data = func()
	if type(data) ~= "table" then
		return nil, "Return type is not a table"
	end
	return data
end


Review comment (suggestion):
~~FYI, you don't have to reverse the string and the index here, just put your for loop in reverse instead~~

I just realized this can all be done in a single `gsub`
```suggestion
	return accountName:gsub("(.*)[#%-]", "%1#")
```

Code after:
	local largestGroupSize = 0
	local largestGroupIndex = 1
	for i, socketGroup in ipairs(self.build.skillsTab.socketGroupList) do
		if #socketGroup.gemList > largestGroupSize then
			largestGroupSize = #socketGroup.gemList
			largestGroupIndex = i
		end
	end
	return largestGroupIndex
end

function HexToChar(x)
	return string.char(tonumber(x, 16))
end

function ReplaceDiscriminatorSafely(accountName)
	return accountName:gsub("(.*)[#%-]", "%1#")
end

function UrlDecode(url)
	if url == nil then
		return
	end
	url = url:gsub("+", " ")
	url = url:gsub("%%(%x%x)", HexToChar)
	return url
end

function ImportTabClass:ProcessJSON(json)
	local func, errMsg = loadstring("return "..jsonToLua(json))
	if errMsg then
		return nil, errMsg
	end
	setfenv(func, { }) -- Sandbox the function just in case
	local data = func()
	if type(data) ~= "table" then
		return nil, "Return type is not a table"
	end
	return data
end