120

I am using fetch() to grab data from api server. My error looks like this:

Uncaught (in promise) SyntaxError: Unexpected end of input at 
  fetch.then.blob.

Can you please tell me what am I doing wrong.

const weatherAPi ='https://www.metaweather.com/api/location/523920';
fetch(weatherAPi, {
  mode: 'no-cors'
}).then(blob => blob.json())
  .then(data => console.log(data))
5
  • 1
    I only see this error when I test it in the browser console Commented Aug 15, 2017 at 16:27
  • 6
    The problem is that the response you're getting is not a valid json (it looks like it's null) Commented Aug 15, 2017 at 16:29
  • 5
    What an absolutely thoughtless security measure. If I want to fetch publicly hosted JSON as a bad actor, it's easy using other means. If I want to fetch it as a good actor, it's impossible. Commented Oct 2, 2019 at 20:05
  • 1
    Does this answer your question? Handle response - SyntaxError: Unexpected end of input when using mode: 'no-cors' Commented Nov 20, 2020 at 9:28
  • For me it was because the endpoint wasn't returning any data. I made the endpoint return json data and the error disappeared. Commented Dec 1, 2022 at 11:50

11 Answers 11

153

Opaque Responses

A response for a no-cors request to a cross-origin resource has a response type of 'opaque'. If you log the response before trying to turn it to JSON, you will see a type of "opaque".

Opaque types are listed as "severely restricted" as explained in the fetch spec on whatwg.org.

An opaque filtered response is a filtered response whose type is "opaque", url list is the empty list, status is 0, status message is the empty byte sequence, header list is empty, body is null, and trailer is empty.

They cannot currently be read when the type is opaque as explained on Google's docs on the opaque type.

An opaque response is for a request made for a resource on a different origin that doesn't return CORS headers. With an opaque response, we won't be able to read the data returned or view the status of the request, meaning we can't check if the request was successful or not. With the current fetch() implementation, it's not possible to make requests for resources of a different origin from the window global scope.

Enable CORS support on your server

This can be environment-dependent or language-dependent. For example, you can change CORS settings within Nginx's environment by changing your server config, or you can specify headers within your application code such as in PHP.

I highly recommend reading the Mozilla documentation on CORS requests and also Access-Control-Allow-Origin.

An example in PHP:

<?php
header("Access-Control-Allow-Origin: *");  // "*" could also be a site such as http://www.example.com
Sign up to request clarification or add additional context in comments.

4 Comments

what is the solution for it... If I remove no-cors then it throws error for cross origin
@AnthonyWinzlet, You'll need to update the CORS headers on the server you are trying to request information from. These CORS policies are in place for security purposes. This is a fairly lengthy read, but here is a great resource on CORS requests.
Often, you will get a CORS error when the server is throwing the error and CORS has nothing to do with it. So, I always start checking the server side code for a problem if I know that I know that my CORS settings are correct.
When the server side sets the header Access-Control-Allow-Origin: * which allow all cors request, the client use fetch to send request no need no-cors mode anymore
95

I had the same problem. in my case it wasn't caused by the response type of 'opaque' as the solution pointed. This code cause an error with empty response, because 'fetch' doesn't accept responses with empty body :

return fetch(urlToUser, parameters)
.then(response => {
  return response.json()
})
.then((data) => {
  resolve(data)
})
.catch((error) => {
  reject(error)
})

Instead, in my case this works better :

return fetch(urlToUser, parameters)
.then(response => {
  return response.text()
})
.then((data) => {
  resolve(data ? JSON.parse(data) : {})
})
.catch((error) => {
  reject(error)
})

Gettting the text doesn't give the error even with the empty body. Then check if data exists and resolve. I hope it helps :-)

6 Comments

Same solution is recommended by Github's fetch polyfill team too: github.com/github/fetch/issues/268#issuecomment-176544728
response.text() is empty for me
i like this solution. I ran into the same issue with some of my REST Responses having no body while the core service requires JSON. This has solved it quite nicely! Thanks.
What is the resolve() for? Is it a dummy example method to work with data?
This works perfectly for me where a PUT call to an external API that returns a HTTP 204.
|
17

Lots of good responses but I chose this:

      const response = await fetch(url, {
        method: 'GET',
        headers: {
          Authorization: 'Bearer ' + accessToken
        }
      });
      const string = await response.text();
      const json = string === "" ? {} : JSON.parse(string);
      return json;

Comments

9

(for people coming later but dealing with this problem "Unexpected end of JSON input")

The problem in many times is server error or just invalid URL but you can't see it because all examples on internet how to work with fetch are missing one important part - the server or network failure.

The correct way how to deal with fetch is to test response if contains errors before conversion to json.

Check the part of the first then in example where resp.ok is tested:

async function fetchData() {
    return await fetch('https://your-server.com/some-NOt-existing-url/')
        .then(resp => {
            if (!resp.ok) {
                throw `Server error: [${resp.status}] [${resp.statusText}] [${resp.url}]`;
            }
            return resp.json();
        })
        .then(receivedJson => {
            // your code with json here...
        })
        .catch(err => {
            console.debug("Error in fetch", err);
            setErrors(err)
        });
}

2 Comments

> for people coming later Your answer does not answer the OP at all. The problem is due to a CORS conflict with the Fetch API wherein you get an opaque response as explained by the selected answer.
@MaximilianBurszley the "Unexpected end of input at fetch..." error has multiple reasons and this is one of them as you can see by the likes of the answer. CORS is equivalent to invalid url problem because CORS policy is blocking the request what leads to network error which is detectable by this code.
7

You need to have in the header of php or another server endpoint the row:

<?php
header('Access-Control-Allow-Origin: *');
//or
header('Access-Control-Allow-Origin: http://example.com');

// Reading JSON POST using PHP
$json = file_get_contents('php://input');
$jsonObj = json_decode($json);

// Use $jsonObj
print_r($jsonObj->message);

...
// End php
?>

Model of working fetch code with POST request is:

const data = {
        optPost: 'myAPI',
        message: 'We make a research of fetch'
    };
const endpoint = 'http://example.com/php/phpGetPost.php';

fetch(endpoint, {
    method: 'POST',
    body: JSON.stringify(data)
})
.then((resp) => resp.json())
.then(function(response) {
    console.info('fetch()', response);
    return response;
});

1 Comment

You can also use the online cors proxy cors-anywhere.herokuapp.com to circumvent this issue without writing PHP yourself.
3

Adding to Pibo's answer...

I dont know how this happened, but I solved it just by changing

return fetch(url, {
        mode: "no-cors" // <----------------
    })
    .then((res)=>{
        return res.text();
    })
    .then((data)=>{
        console.log(data);
        return new Promise((resolve, reject)=>{
            resolve(data ? JSON.parse(data) : {})
        })
    })

to

return fetch(url, {
        mode: "cors" // <----------------
    })
    .then((res)=>{
        return res.text();
    })
    .then((data)=>{
        console.log(data);
        return new Promise((resolve, reject)=>{
            resolve(data ? JSON.parse(data) : {})
        })
    })

1 Comment

my case was to remove completely the 'no-cors'. The server (SpringBoot) took care of the cors origin already.
1

You met with the CORS origin policy problem. To tackle this you need rights to access the server side API. In particular, you need to add a line in the header of php or another server endpoint:

<?php
header('Access-Control-Allow-Origin: *');
//or
header('Access-Control-Allow-Origin: http://example.com');

// Reading JSON POST using PHP
$json = file_get_contents('php://input');
$jsonObj = json_decode($json);

// Use $jsonObj
print_r($jsonObj->message);

...
// End php
?>

Also, make sure NOT to have in the header of your server endpoint:

header("Access-Control-Allow-Credentials" : true);

Model of working fetch code with POST request is:

const data = {
        optPost: 'myAPI',
        message: 'We make a research of fetch'
    };
const endpoint = 'http://example.com/php/phpGetPost.php';

fetch(endpoint, {
    method: 'POST',
    body: JSON.stringify(data)
})
.then((resp) => resp.json())
.then(function(response) {
    console.info('fetch()', response);
    return response;
});

2 Comments

Uncaught (in promise) SyntaxError: Unexpected end of JSON input
This was the same code I had, but didnt work... Just copy from stackoverflow, and the code say "Hey! This is not yours, I will do it this time :D" -_-
1

I solved this by removing the header in the request :

Before :

// get articles
var Req_articles = new FormData();
Req_articles.append('set', 'get_articles');

fetch('/', {
    method: 'POST', // *GET, POST, PUT, DELETE, etc.
    headers: {
      'Content-Type': 'application/json'
    },
    mode: 'same-origin', // no-cors, *cors, same-origin
    cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
    credentials: 'same-origin', // include, *same-origin, omit
    body: Req_articles,
}).then( response => response.json() )
.then((data) => {

    console.log(data;
});

After :

// get articles
var Req_articles = new FormData();
Req_articles.append('set', 'get_articles');

fetch('/', {
    method: 'POST', // *GET, POST, PUT, DELETE, etc.
    mode: 'same-origin', // no-cors, *cors, same-origin
    cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
    credentials: 'same-origin', // include, *same-origin, omit
    body: Req_articles,
}).then( response => response.json() )
.then((data) => {

    console.log(data;
});

In fact it's logical, because what I sent is of the type "content-type: multipart/form-data" and not "application/json"

Hope to help

Comments

0

unexpected end of input

 // .then((response) => response.json()) .  // commit out this part

https://github.com/github/fetch/issues/268

fetch(url, {
    method: 'POST',
    body: JSON.stringify(requestPayload),           
    headers: {
        'Content-type': 'application/json; charset=UTF-8',
        Authorization: 'Bearer ' + token,
    },
})
    // .then((response) => response.json()) .  // commit out this part
    .then((json) => {
        console.log("response :- ", json);
        getCheckedInTrailersList();
    }).catch((error)=>{
        console.log("Api call error ", error.message);
        alert(error.message);
});

Comments

0

As an alternative to @Pibo's solution, instead of fixing the fetch() at client side, you can fix it at server side by checking the nullity of your return value and change it to {} (or [] if an array is expected).

Below is an example for Node.js:

site.get("/api/get-industries", (req, res) => {
    db.accountDB.getPresetData("Industries")
        .then((result) => {
            // If the result is null, return an empty array instead.
            res.send(result ? result : []);
        })
        .catch((error) => {
            res.status(500).send(error);
        });

});

Comments

-1

@KevBot save me. I meet the problem accidentally. The request method works all along but it failed suddenly. Now I know it is because I add the 'no-cors' option to fetch method. I request multiple api. Some need the option some don't. So I modified my code like the following:

// determine whether add mode option to fetch method
const option =is_outer? {
  mode: 'no-cors'
} : {};
ret = fetch(url, option).then(data => {
    if (url.endsWith('txt')) {
      return data.text()
     } else {
      const j = data.json();
     ...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.