"SyntaxError: Unexpected token < in JSON at position 0"

1,308,592

Solution 1

The wording of the error message corresponds to what you get from Google Chrome when you run JSON.parse('<...'). I know you said the server is setting Content-Type:application/json, but I am led to believe the response body is actually HTML.

Feed.js:94 undefined "parsererror" "SyntaxError: Unexpected token < in JSON at position 0"

with the line console.error(this.props.url, status, err.toString()) underlined.

The err was actually thrown within jQuery, and passed to you as a variable err. The reason that line is underlined is simply because that is where you are logging it.

I would suggest that you add to your logging. Looking at the actual xhr (XMLHttpRequest) properties to learn more about the response. Try adding console.warn(xhr.responseText) and you will most likely see the HTML that is being received.

Solution 2

You're receiving HTML (or XML) back from the server, but the dataType: json is telling jQuery to parse as JSON. Check the "Network" tab in Chrome dev tools to see contents of the server's response.

Solution 3

This ended up being a permissions problem for me. I was trying to access a url I didn't have authorization for with cancan, so the url was switched to users/sign_in. the redirected url responds to html, not json. The first character in a html response is <.

Solution 4

In my case, I was getting this running webpack, and it turned out to be some corruption somewhere in the local node_modules dir.

rm -rf node_modules
npm install

...was enough to get it working right again.

Solution 5

SyntaxError: Unexpected token < in JSON at position 0


You are getting an HTML file (or XML) instead of json.

Html files begin with <!DOCTYPE html>.

I "achieved" this error by forgetting the https:// in my fetch method:

fetch(`/api.github.com/users/${login}`)
    .then(response => response.json())
    .then(setData);

I verified my hunch:

I logged the response as text instead of JSON.

fetch(`/api.github.com/users/${login}`)
    .then(response => response.text())
    .then(text => console.log(text))
    .then(setData);

Yep, an html file.

Solution:

I fixed the error by adding back the https:// in my fetch method.

fetch(`https://api.github.com/users/${login}`)
    .then(response => response.json())
    .then(setData)
    .catch(error => (console.log(error)));
Share:
1,308,592

Related videos on Youtube

Cameron Sima
Author by

Cameron Sima

Full stack React.js and Spring developer in the fintech industry.

Updated on July 08, 2022

Comments

  • Cameron Sima
    Cameron Sima almost 2 years

    In a React app component which handles Facebook-like content feeds, I am running into an error:

    Feed.js:94 undefined "parsererror" "SyntaxError: Unexpected token < in JSON at position 0

    I ran into a similar error which turned out to be a typo in the HTML within the render function, but that doesn't seem to be the case here.

    More confusingly, I rolled the code back to an earlier, known-working version and I'm still getting the error.

    Feed.js:

    import React from 'react';
    
    var ThreadForm = React.createClass({
      getInitialState: function () {
        return {author: '', 
                text: '', 
                included: '',
                victim: ''
                }
      },
      handleAuthorChange: function (e) {
        this.setState({author: e.target.value})
      },
      handleTextChange: function (e) {
        this.setState({text: e.target.value})
      },
      handleIncludedChange: function (e) {
        this.setState({included: e.target.value})
      },
      handleVictimChange: function (e) {
        this.setState({victim: e.target.value})
      },
      handleSubmit: function (e) {
        e.preventDefault()
        var author = this.state.author.trim()
        var text = this.state.text.trim()
        var included = this.state.included.trim()
        var victim = this.state.victim.trim()
        if (!text || !author || !included || !victim) {
          return
        }
        this.props.onThreadSubmit({author: author, 
                                    text: text, 
                                    included: included,
                                    victim: victim
                                  })
        this.setState({author: '', 
                      text: '', 
                      included: '',
                      victim: ''
                      })
      },
      render: function () {
        return (
        <form className="threadForm" onSubmit={this.handleSubmit}>
          <input
            type="text"
            placeholder="Your name"
            value={this.state.author}
            onChange={this.handleAuthorChange} />
          <input
            type="text"
            placeholder="Say something..."
            value={this.state.text}
            onChange={this.handleTextChange} />
          <input
            type="text"
            placeholder="Name your victim"
            value={this.state.victim}
            onChange={this.handleVictimChange} />
          <input
            type="text"
            placeholder="Who can see?"
            value={this.state.included}
            onChange={this.handleIncludedChange} />
          <input type="submit" value="Post" />
        </form>
        )
      }
    })
    
    var ThreadsBox = React.createClass({
      loadThreadsFromServer: function () {
        $.ajax({
          url: this.props.url,
          dataType: 'json',
          cache: false,
          success: function (data) {
            this.setState({data: data})
          }.bind(this),
          error: function (xhr, status, err) {
            console.error(this.props.url, status, err.toString())
          }.bind(this)
        })
      },
      handleThreadSubmit: function (thread) {
        var threads = this.state.data
        var newThreads = threads.concat([thread])
        this.setState({data: newThreads})
        $.ajax({
          url: this.props.url,
          dataType: 'json',
          type: 'POST',
          data: thread,
          success: function (data) {
            this.setState({data: data})
          }.bind(this),
          error: function (xhr, status, err) {
            this.setState({data: threads})
            console.error(this.props.url, status, err.toString())
          }.bind(this)
        })
      },
      getInitialState: function () {
        return {data: []}
      },
      componentDidMount: function () {
        this.loadThreadsFromServer()
        setInterval(this.loadThreadsFromServer, this.props.pollInterval)
      },
      render: function () {
        return (
        <div className="threadsBox">
          <h1>Feed</h1>
          <div>
            <ThreadForm onThreadSubmit={this.handleThreadSubmit} />
          </div>
        </div>
        )
      }
    })
    
    module.exports = ThreadsBox
    

    In Chrome developer tools, the error seems to be coming from this function:

     loadThreadsFromServer: function loadThreadsFromServer() {
        $.ajax({
          url: this.props.url,
          dataType: 'json',
          cache: false,
          success: function (data) {
            this.setState({ data: data });
          }.bind(this),
          error: function (xhr, status, err) {
            console.error(this.props.url, status, err.toString());
          }.bind(this)
        });
      },
    

    with the line console.error(this.props.url, status, err.toString() underlined.

    Since it looks like the error seems to have something to do with pulling JSON data from the server, I tried starting from a blank db, but the error persists. The error seems to be called in an infinite loop presumably as React continuously tries to connect to the server and eventually crashes the browser.

    EDIT:

    I've checked the server response with Chrome dev tools and Chrome REST client, and the data appears to be proper JSON.

    EDIT 2:

    It appears that though the intended API endpoint is indeed returning the correct JSON data and format, React is polling http://localhost:3000/?_=1463499798727 instead of the expected http://localhost:3001/api/threads.

    I am running a webpack hot-reload server on port 3000 with the express app running on port 3001 to return the backend data. What's frustrating here is that this was working correctly the last time I worked on it and can't find what I could have possibly changed to break it.

    • Quentin
      Quentin almost 8 years
      That suggests that your "JSON" is actually HTML. Look at the data you are getting back from the server.
    • apsillers
      apsillers almost 8 years
      This is the error you get if you do something like JSON.parse("<foo>") -- a JSON string (which you expect with dataType: 'json') cannot begin with <.
    • maurycy
      maurycy almost 8 years
      As @quantin said, it can be html, maybe error of some sort, try the same url with some rest clients
    • Cameron Sima
      Cameron Sima almost 8 years
      like I mentioned, i tried it with an empty db (which returns simply []) and it still gives the same error
    • Kevin Suttle
      Kevin Suttle over 7 years
      You most likely need to proxy API requests depending on your NODE_ENV. See this: github.com/facebookincubator/create-react-app/blob/master/…
    • Shazam
      Shazam almost 6 years
      @apsillers I think this is my problem. I am storing HTML strings with markup in my JSON object for display. Do I need to escape all the HTML characters for this to work?
    • Khurshid Ansari
      Khurshid Ansari about 4 years
      my suggetion to use github.com/axios/axios
    • Dante
      Dante almost 3 years
      I encountered this error as I used if($_POST['key']) instead of if(isset($_POST['key'])) .Although this is a very silly and an amateur mistake, I hope some LIY dev like me might find this useful.
    • RohitAneja
      RohitAneja over 2 years
      Check your package-lock.json, if there are merge conflicts, it will show this error.
    • Marina Kim
      Marina Kim almost 2 years
      Hi, in my case the same issue resolved when I simply changed the API uri from root "/" to something else, e.g. app.get("/data", (req, res)...) Hope it helps someone
  • Cameron Sima
    Cameron Sima almost 8 years
    I checked, and it appears to be returning properly formatted json. Here's the response header: Access-Control-Allow-Origin:* Cache-Control:no-cache Content-Length:2487 Content-Type:application/json; charset=utf-8 Date:Tue, 17 May 2016 15:34:00 GMT ETag:W/"9b7-yi1/G0RRpr0DlOVc9u7cMw" X-Powered-By:Express
  • Cameron Sima
    Cameron Sima almost 8 years
    Thanks, I did this and you're right -- react is polling the wrong url and is returning the contents of index.html. I just can't find out why.
  • user2441511
    user2441511 over 7 years
    Thanks for the additional debugging statement, although I needed to use console.warn(jqxhr.responseText). That was very helpful in diagnosing my problem.
  • 700 Software
    700 Software over 7 years
    @Mimi314159, console.log, console.warn and console.error will all write to your Console. However, the Console will usually provide Logging Filter options, so be sure that those are enabled or disabled as you prefer.
  • Ivan Prihhodko
    Ivan Prihhodko almost 7 years
    This is one of the most bizarre answers I've ever seen on Stackoverflow.
  • Derek
    Derek over 6 years
    In my case, a PHP error was occuring which caused the server to return HTML rather than valid JSON.
  • Jason Marsell
    Jason Marsell over 6 years
    I had the same, although in ASP.NET MVC. For other .NETters, I had forgotten to decorate my action with the [AllowAnonymous] attribute so the framework was trying to return me the unauthorized error in HTML which was crashing my AJAX call.
  • DJ2
    DJ2 about 6 years
    @AVI I believe you have to specify the MIME type in your resource class. (e.g) @Produces(MediaType.APPLICATION_JSON)
  • Harshith Rai
    Harshith Rai over 5 years
    Please elaborate while giving answers rather than giving one liners, unless they outright solve answers. The explanation would help the answer-seekers understand the solution better.
  • Andrew Gray
    Andrew Gray about 5 years
    Hi there! When posting a comment, make sure it's entirely applicable to the actual question being asked. Your answer could be better if you tell us why exactly writing comments in a styles.less file could possibly solve what appears to be a back-end server code issue.
  • Mahesh
    Mahesh over 4 years
    along with this, I tried removing package-lock.json. Then it worked for me.
  • sumesh
    sumesh over 3 years
    Please use the answer option if you are sure about the solution, else you can choose to write it as a comment to the question.
  • Vortex
    Vortex over 3 years
    In my case this works therefore writing it as answer.
  • Shivam Jha
    Shivam Jha over 3 years
    You can also got to Developer Settings -> Network Tab to see the response which you are actually getting. This happens when you are running backend and frontend on the same sever (e.g., localhost). To fix that, in the package.json inside your React root project folder, add this line: "proxy": "http://localhost:5000" , (or your port instead of 5000 you want your request back).
  • Eliezer Berlin
    Eliezer Berlin over 3 years
    The reason it's happening is because you're getting an HTML response instead of a JSON response. Your response probably begins with <head> or <body>, with the first letter being "<".
  • Tim Erickson
    Tim Erickson about 2 years
    Think carefully about that logic. Parsing undefined is only ONE way to get that error. Trying (for example) JSON.parse('<') is another.
  • marc-stupid
    marc-stupid about 2 years
    so what is the answer in that case
  • crwils
    crwils about 2 years
    Removing node modules and a fresh npm install worked for me.
  • Bruno71
    Bruno71 about 2 years
    I had a similar issue with my Vue site. Locally it worked fine, but once published, I would get 404 errors when refreshing URLs. It had to do with rewriting the path for the API. I followed the Vue Router instructions here ...but it still wasn't working. I had to exclude the js/css/img directories from the redirect also.