Relay: GraphQLRange cannot find a segment that has the cursor

Created on 8 Jul 2016  ·  11Comments  ·  Source: facebook/relay

I'm receiving the following error after a save comment mutation

GraphQLRange cannot find a segment that has the cursor: MTQ2NzkxNTE5NA==

this only happens after I ask for more comments before adding a new one

this is my createContainer code:

export default Relay.createContainer(CommentsDetails, {
  initialVariables: {
    count: 10,
  },

  fragments: {
    post: () => Relay.QL`
      fragment on Post {
        id,
        comments(first: $count) {
          edges {
            cursor,
            node {
              createdAt,
              ${Comment.getFragment('comment')},
            }
          },
          pageInfo {
            hasNextPage,
            hasPreviousPage,
            startCursor,
            endCursor,
          },
        }
      },
    `,
  },
});

this is my save comment mutation

import Relay from 'react-relay';

export default class SaveCommentMutation extends Relay.Mutation {
  getMutation() {
    return Relay.QL `mutation {
      saveComment
    }`;
  }

  getVariables() {
    const { post, body } = this.props;
    console.log('variables: ', post, body, this.props);
    return {
      post_id: post.id,
      body,
    }
  }

  getFatQuery() {
    return Relay.QL`
      fragment on saveCommentPayload {
        commentEdge,
        post {
          id,
          comments,
        },
        error,
      }
    `;
  }
  getConfigs() {
    return [
      {
        type: 'FIELDS_CHANGE',
        fieldIDs: {
          post: this.props.post.id,
        },
      },
      {
        type: 'RANGE_ADD',
        parentName: 'post',
        parentID: this.props.post.id,
        connectionName: 'comments',
        edgeName: 'commentEdge',
        rangeBehaviors: {
          '': 'append',
          'orderby(createdAt)': 'append',
      },
    }];
  }

  getOptimisticResponse() {
    const { post, body } = this.props;

    return {
      post: {
        id: post.id,
      },
      commentEdge: {
        node: {
          body: body,
          createdAt: new Date().toUTCString(),
          user: {
            name: 'anonymous',
          }
        }
      }
    };
  }
}

this is the generated graphql query, it works if I try on graphql

mutation SaveCommentMutation($input_0:saveCommentInput!) {
  saveComment(input:$input_0) {
    clientMutationId,
    ...F5,
    ...F6
  }
}
fragment F0 on Post {
  id
}
fragment F1 on Comment {
  id,
  body,
  createdAt,
  user {
    username,
    name,
    id
  }
}
fragment F2 on Post {
  id,
  _comments2g8zcs:comments(first:10) {
    edges {
      cursor,
      node {
        createdAt,
        id,
        ...F1
      }
    },
    pageInfo {
      hasNextPage,
      hasPreviousPage,
      startCursor,
      endCursor
    }
  }
}
fragment F3 on Post {
  id,
  _comments3Cdb4n:comments(after:"MTQ2NzkyMDExNQ==",first:10) {
    edges {
      cursor,
      node {
        createdAt,
        id,
        ...F1
      }
    },
    pageInfo {
      hasNextPage,
      hasPreviousPage,
      startCursor,
      endCursor
    }
  }
}
fragment F4 on Post {
  id,
  _comments1Z6zk7:comments(after:"MTQ2NzkxNTE5NA==",first:10) {
    edges {
      cursor,
      node {
        createdAt,
        id,
        ...F1
      }
    },
    pageInfo {
      hasNextPage,
      hasPreviousPage,
      startCursor,
      endCursor
    }
  }
}
fragment F5 on saveCommentPayload {
  post {
    id,
    ...F0,
    id,
    id,
    ...F2,
    ...F3,
    ...F4
  }
}
fragment F6 on saveCommentPayload {
  commentEdge {
    cursor,
    __typename,
    node {
      createdAt,
      id,
      body,
      user {
        username,
        name,
        id
      }
    }
  },
  post {
    id,
    ...F0,
    id,
    id
  }
}

Most helpful comment

Just stumbling around in the dark here, but in addition to “2” above can you try to replace rangeBehaviors with a function that always returns GraphQLMutatorConstants.RANGE_OPERATIONS.APPEND?

rangeBehaviors: (connectionArgs: {[argName: string]: string}) => {
  // $Enum<GraphQLMutatorConstants.RANGE_OPERATIONS>
  return 'append';
}

All 11 comments

Disclaimer: I’m not a Relay expert, but I’ve done my fair share of Relay debugging :wink:. These are some tricks that will hopefully either help identify the error or give us more information.

  1. Since the query works in GraphiQL, try removing the getOptimisticResponse function and see if that helps. You may not be including enough information in the optimistic response.
  2. Maybe try removing orderby(createdAt) from rangeBehaviors. In both scenarios you’re appending.

See if that helps. It would also be very helpful to see what your server returns for the generated query. It may be possible that you’re not implementing the Relay spec correctly (can’t be sure without seeing the result).

I think we’ll need more information though to continue debugging.

Just stumbling around in the dark here, but in addition to “2” above can you try to replace rangeBehaviors with a function that always returns GraphQLMutatorConstants.RANGE_OPERATIONS.APPEND?

rangeBehaviors: (connectionArgs: {[argName: string]: string}) => {
  // $Enum<GraphQLMutatorConstants.RANGE_OPERATIONS>
  return 'append';
}

@sibelius Have any of these suggestions helped? We can help debug more effectively if you're able to provide a sample mutation response.

this is the response:

{
  "response": {
  "saveComment": {
    "clientMutationId": "0",
      "post": {
      "id": "UG9zdDo2YzViZmQxMy0zYTE3LTQyMjUtYmQzYy1jZTEzYjc0ZjU5ODA=",
        "_comments2g8zcs": {
        "edges": [
          {
            "cursor": "MTQ2ODM0ODA4Mg==",
            "node": {
              "createdAt": 1468348082,
              "id": "Q29tbWVudDoyZGRmMGMzNS1lNzM3LTRjYWQtOGEwZC0yNjQxMjhmNmE0MDQ=",
              "body": "More awesome",
              "user": {
                "username": null,
                "name": "Anonymous",
                "id": "VXNlcjoxZjI3YzU3OS0yODAzLTQyNjEtOTQ5YS00OGZlMDZiZjk4N2E="
              }
            }
          },
          {
            "cursor": "MTQ2ODM0Nzc0OQ==",
            "node": {
              "createdAt": 1468347749,
              "id": "Q29tbWVudDphNDg5YmU5Mi01NzVjLTQxMzQtYjRkMC00OWUxYzY3NjQ5MTU=",
              "body": "Awesome",
              "user": {
                "username": null,
                "name": "Anonymous",
                "id": "VXNlcjoxZjI3YzU3OS0yODAzLTQyNjEtOTQ5YS00OGZlMDZiZjk4N2E="
              }
            }
          },
          {
            "cursor": "MTQ2ODM0NzUzNA==",
            "node": {
              "createdAt": 1468347534,
              "id": "Q29tbWVudDozMTAwM2M1ZC05MDk5LTQzZTYtOTY3NS05NDBjNzhlNDgwMzk=",
              "body": "Great",
              "user": {
                "username": null,
                "name": "Anonymous",
                "id": "VXNlcjoxZjI3YzU3OS0yODAzLTQyNjEtOTQ5YS00OGZlMDZiZjk4N2E="
              }
            }
          },
          {
            "cursor": "MTQ2ODMzMTkyNw==",
            "node": {
              "createdAt": 1468331927,
              "id": "Q29tbWVudDo1Y2Y0ZDU3Yy1hMzhmLTRjZTctYWI0My1lYjgxYWE4NDc2NTc=",
              "body": "Good",
              "user": {
                "username": null,
                "name": "Anonymous",
                "id": "VXNlcjoxZjI3YzU3OS0yODAzLTQyNjEtOTQ5YS00OGZlMDZiZjk4N2E="
              }
            }
          },
          {
            "cursor": "MTQ2ODMyMTM3MQ==",
            "node": {
              "createdAt": 1468321371,
              "id": "Q29tbWVudDo0NjQxZjU1ZS04ZWUwLTQyZTAtOWZlNC01M2YwNjUxZjMzZWE=",
              "body": "Working",
              "user": {
                "username": null,
                "name": "Anonymous",
                "id": "VXNlcjoxZjI3YzU3OS0yODAzLTQyNjEtOTQ5YS00OGZlMDZiZjk4N2E="
              }
            }
          },
          {
            "cursor": "MTQ2ODMyMTMwNw==",
            "node": {
              "createdAt": 1468321307,
              "id": "Q29tbWVudDo3YzI1MGY1Mi0zNjNkLTRlZGItOTAwMy05ZDc4Zjk1ZDIyZDI=",
              "body": "Awesome",
              "user": {
                "username": null,
                "name": "Anonymous",
                "id": "VXNlcjoxZjI3YzU3OS0yODAzLTQyNjEtOTQ5YS00OGZlMDZiZjk4N2E="
              }
            }
          },
          {
            "cursor": "MTQ2ODMyMTI3OQ==",
            "node": {
              "createdAt": 1468321279,
              "id": "Q29tbWVudDo1N2NhNTQxYy02NDU3LTQ5MWMtODQzMy01ZTRmZjI5OTdjODc=",
              "body": "Again",
              "user": {
                "username": null,
                "name": "Anonymous",
                "id": "VXNlcjoxZjI3YzU3OS0yODAzLTQyNjEtOTQ5YS00OGZlMDZiZjk4N2E="
              }
            }
          },
          {
            "cursor": "MTQ2ODMyMTI2MQ==",
            "node": {
              "createdAt": 1468321261,
              "id": "Q29tbWVudDoxNTEwZmI5OS1lMjVlLTQxNzMtYWJiMy02OTk4NjM5ZDJhYTU=",
              "body": "More",
              "user": {
                "username": null,
                "name": "Anonymous",
                "id": "VXNlcjoxZjI3YzU3OS0yODAzLTQyNjEtOTQ5YS00OGZlMDZiZjk4N2E="
              }
            }
          },
          {
            "cursor": "MTQ2ODMyMTA3Mg==",
            "node": {
              "createdAt": 1468321072,
              "id": "Q29tbWVudDoyYmU1NzJiZS1iZWM5LTQwNWItYjBjNC1lYmFmODk3MzhmOGY=",
              "body": "Ok",
              "user": {
                "username": null,
                "name": "Anonymous",
                "id": "VXNlcjoxZjI3YzU3OS0yODAzLTQyNjEtOTQ5YS00OGZlMDZiZjk4N2E="
              }
            }
          },
          {
            "cursor": "MTQ2ODMyMTA1Mw==",
            "node": {
              "createdAt": 1468321053,
              "id": "Q29tbWVudDo1NGE4YjZjNi04YjU1LTQzOTctOWUwNy0yNzExMmJjOWZiODM=",
              "body": "Great",
              "user": {
                "username": null,
                "name": "Anonymous",
                "id": "VXNlcjoxZjI3YzU3OS0yODAzLTQyNjEtOTQ5YS00OGZlMDZiZjk4N2E="
              }
            }
          }
        ],
          "pageInfo": {
          "hasNextPage": true,
            "hasPreviousPage": false,
            "startCursor": null,
            "endCursor": null
        }
      },
      "_comments41V1M2": {
        "edges": [
          {
            "cursor": "MTQ2ODM0ODA4Mg==",
            "node": {
              "createdAt": 1468348082,
              "id": "Q29tbWVudDoyZGRmMGMzNS1lNzM3LTRjYWQtOGEwZC0yNjQxMjhmNmE0MDQ=",
              "body": "More awesome",
              "user": {
                "username": null,
                "name": "Anonymous",
                "id": "VXNlcjoxZjI3YzU3OS0yODAzLTQyNjEtOTQ5YS00OGZlMDZiZjk4N2E="
              }
            }
          },
          {
            "cursor": "MTQ2ODM0Nzc0OQ==",
            "node": {
              "createdAt": 1468347749,
              "id": "Q29tbWVudDphNDg5YmU5Mi01NzVjLTQxMzQtYjRkMC00OWUxYzY3NjQ5MTU=",
              "body": "Awesome",
              "user": {
                "username": null,
                "name": "Anonymous",
                "id": "VXNlcjoxZjI3YzU3OS0yODAzLTQyNjEtOTQ5YS00OGZlMDZiZjk4N2E="
              }
            }
          },
          {
            "cursor": "MTQ2ODM0NzUzNA==",
            "node": {
              "createdAt": 1468347534,
              "id": "Q29tbWVudDozMTAwM2M1ZC05MDk5LTQzZTYtOTY3NS05NDBjNzhlNDgwMzk=",
              "body": "Great",
              "user": {
                "username": null,
                "name": "Anonymous",
                "id": "VXNlcjoxZjI3YzU3OS0yODAzLTQyNjEtOTQ5YS00OGZlMDZiZjk4N2E="
              }
            }
          },
          {
            "cursor": "MTQ2ODMzMTkyNw==",
            "node": {
              "createdAt": 1468331927,
              "id": "Q29tbWVudDo1Y2Y0ZDU3Yy1hMzhmLTRjZTctYWI0My1lYjgxYWE4NDc2NTc=",
              "body": "Good",
              "user": {
                "username": null,
                "name": "Anonymous",
                "id": "VXNlcjoxZjI3YzU3OS0yODAzLTQyNjEtOTQ5YS00OGZlMDZiZjk4N2E="
              }
            }
          },
          {
            "cursor": "MTQ2ODMyMTM3MQ==",
            "node": {
              "createdAt": 1468321371,
              "id": "Q29tbWVudDo0NjQxZjU1ZS04ZWUwLTQyZTAtOWZlNC01M2YwNjUxZjMzZWE=",
              "body": "Working",
              "user": {
                "username": null,
                "name": "Anonymous",
                "id": "VXNlcjoxZjI3YzU3OS0yODAzLTQyNjEtOTQ5YS00OGZlMDZiZjk4N2E="
              }
            }
          },
          {
            "cursor": "MTQ2ODMyMTMwNw==",
            "node": {
              "createdAt": 1468321307,
              "id": "Q29tbWVudDo3YzI1MGY1Mi0zNjNkLTRlZGItOTAwMy05ZDc4Zjk1ZDIyZDI=",
              "body": "Awesome",
              "user": {
                "username": null,
                "name": "Anonymous",
                "id": "VXNlcjoxZjI3YzU3OS0yODAzLTQyNjEtOTQ5YS00OGZlMDZiZjk4N2E="
              }
            }
          },
          {
            "cursor": "MTQ2ODMyMTI3OQ==",
            "node": {
              "createdAt": 1468321279,
              "id": "Q29tbWVudDo1N2NhNTQxYy02NDU3LTQ5MWMtODQzMy01ZTRmZjI5OTdjODc=",
              "body": "Again",
              "user": {
                "username": null,
                "name": "Anonymous",
                "id": "VXNlcjoxZjI3YzU3OS0yODAzLTQyNjEtOTQ5YS00OGZlMDZiZjk4N2E="
              }
            }
          },
          {
            "cursor": "MTQ2ODMyMTI2MQ==",
            "node": {
              "createdAt": 1468321261,
              "id": "Q29tbWVudDoxNTEwZmI5OS1lMjVlLTQxNzMtYWJiMy02OTk4NjM5ZDJhYTU=",
              "body": "More",
              "user": {
                "username": null,
                "name": "Anonymous",
                "id": "VXNlcjoxZjI3YzU3OS0yODAzLTQyNjEtOTQ5YS00OGZlMDZiZjk4N2E="
              }
            }
          },
          {
            "cursor": "MTQ2ODMyMTA3Mg==",
            "node": {
              "createdAt": 1468321072,
              "id": "Q29tbWVudDoyYmU1NzJiZS1iZWM5LTQwNWItYjBjNC1lYmFmODk3MzhmOGY=",
              "body": "Ok",
              "user": {
                "username": null,
                "name": "Anonymous",
                "id": "VXNlcjoxZjI3YzU3OS0yODAzLTQyNjEtOTQ5YS00OGZlMDZiZjk4N2E="
              }
            }
          },
          {
            "cursor": "MTQ2ODMyMTA1Mw==",
            "node": {
              "createdAt": 1468321053,
              "id": "Q29tbWVudDo1NGE4YjZjNi04YjU1LTQzOTctOWUwNy0yNzExMmJjOWZiODM=",
              "body": "Great",
              "user": {
                "username": null,
                "name": "Anonymous",
                "id": "VXNlcjoxZjI3YzU3OS0yODAzLTQyNjEtOTQ5YS00OGZlMDZiZjk4N2E="
              }
            }
          }
        ],
          "pageInfo": {
          "hasNextPage": true,
            "hasPreviousPage": true,
            "startCursor": null,
            "endCursor": null
        }
      }
    },
    "commentEdge": {
      "cursor": "MTQ2ODM0ODA4Mg==",
        "__typename": "CommentEdge",
        "node": {
        "createdAt": 1468348082,
          "id": "Q29tbWVudDoyZGRmMGMzNS1lNzM3LTRjYWQtOGEwZC0yNjQxMjhmNmE0MDQ=",
          "body": "More awesome",
          "user": {
          "username": null,
            "name": "Anonymous",
            "id": "VXNlcjoxZjI3YzU3OS0yODAzLTQyNjEtOTQ5YS00OGZlMDZiZjk4N2E="
        }
      }
    }
  }
}
}

@sibelius sorry, but could you include the query with the response :blush:. There are some subtle differences in the query you initially posted and the response, so Relay has likely created a different query (this maybe intended).

Also, were some of the ideas mentioned in this thread effective?

Neither solution worked.

What we did was to save the comment and after that query N + 1 comments to keep the already loaded comments

It is a hacky solution but it works

My guess is a problem with the cursor implementation

As @calebmer mentioned, the query and response don't quite match up so it's a bit hard to debug. However, the overall shape of the mutation seems correct - it fetches something like comments(first: 10) and then comment(first: 10, after: <cursor>). I would try double-checking the cursors:

  • Open the app and fetch some data w/o making mutations. Keep track of all the cursors for the comments you fetch (use RelayNetworkDebug or even just display them onscreen).
  • Initiate a mutation and check that the cursors make sense. Since the mutation only adds one edge we would expect most of the cursors in the mutation response to match up with those that were originally fetched.

I am facing this exact problem.

Update:
The problem was with Edge Name. I was able to solve it by having proper mutation on server and correct fat query on client.

@nikhildaga can you provide a bit more detail about what was wrong, and how you fixed it? This might help @sibelius find the problem.

@josephsavona : Sure.

@sibelius :
Earlier, I didn't have edge field in my fat query and on server mutation. I added those. From your code, it looks like you already have them.

Things to note:
in fat query, I use @relay(pattern: true)
fragment on saveCommentPayload @relay(pattern: true) {
And rangeBeviors in getConfigs is
rangeBehaviors: () => 'prepend',

Thanks again for filing an issue. Without more information it's very hard to debug this - the query and response don't match up, so we can't know for sure whether the issue lies with the cursor values themselves or the query. Generally speaking the query looks correct.

I would recommend the following:

  • Double check your schema to ensure that you are creating cursor values consistently. If the cursor for an edge were to change between the initial fetch and the mutation request, that could cause this error.
  • If that doesn't work and the behavior is causing problems, you may want to use forceFetch instead of setVariables when you load more comments. If it would be too inefficient to load all comments, one option would be to to manually paginate (e.g. request pageInfo.endCursor and use that as the input to after and use forceFetch).

I'm going to close this issue due to inactivity, but please feel free to comment with more information and we'd be happy to reopen and help debug.

Was this page helpful?
0 / 5 - 0 ratings