1

Reporting a possible bug on Youtube Api commentThreads.update

Name of API affected: CommentThreads: update

Issue summary: CommentThreads: update When calling this api to update the topLevelComment returned by CommentThreads.list, I got a 400 error. I was using this API in an internal tool to allow me respond to comments. It was working fine for the last months... and in the last days (~2016-11-07) with no changes on any code on my side, the API started to return a 400 error. I have all my internal comment systems halted right now as I could not figure out how to fix this. Every thing I tried and tested brings me to the 400 error and the message below.

"While this can be a transient error, it usually indicates that the requests input is invalid."

Even using the API console, I got the same errror! My bet? This is a transient error that I hope Google can fix.

Steps to reproduce issue:

  1. Retrieve "heldForReview" threads using CommentThreads.list
  2. Try to update the returned topLevelComment changing ["topLevelComment"]["snippet"]["textOriginal"] = "some text". Optionally, change the "moderationStatus" to "published". The error is the same.
  3. This behaviour can be easily spotted using the Python API samples, specifically the file comment_threads.py from https://github.com/youtube/api-samples/blob/master/python/comment_threads.py

Expected output: The top level comment from Thread should become visible (after setting the moderationStatus to published) and have the "some text" as the first child comment as its answer.

Actual results:

    {
 "error": {
  "errors": [
   {
    "domain": "youtube.commentThread",
    "reason": "processingFailure",
    "message": "The API server failed to successfully process the request. While this can be a transient error, it usually indicates that the requests input is invalid. Check the structure of the \u003ccode\u003ecommentThread\u003c/code\u003e resource in the request body to ensure that it is valid.",
    "locationType": "other",
    "location": "body"
   }
  ],
  "code": 400,
  "message": "The API server failed to successfully process the request. While this can be a transient error, it usually indicates that the requests input is invalid. Check the structure of the \u003ccode\u003ecommentThread\u003c/code\u003e resource in the request body to ensure that it is valid."
 }
}

Notes: I am providing a sample code below.

#!/usr/bin/python
# Usage example:
# python comment_threads.py --channelid='<channel_id>' --videoid='<video_id>' --text='<text>'
import httplib2
import os
import sys

from apiclient.discovery import build_from_document
from apiclient.errors import HttpError
from oauth2client.client import flow_from_clientsecrets
from oauth2client.file import Storage
from oauth2client.tools import argparser, run_flow

# The CLIENT_SECRETS_FILE variable specifies the name of a file that contains

# the OAuth 2.0 information for this application, including its client_id and
# client_secret. You can acquire an OAuth 2.0 client ID and client secret from
# the {{ Google Cloud Console }} at
# {{ https://cloud.google.com/console }}.
# Please ensure that you have enabled the YouTube Data API for your project.
# For more information about using OAuth2 to access the YouTube Data API, see:
#   https://developers.google.com/youtube/v3/guides/authentication
# For more information about the client_secrets.json file format, see:
#   https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
CLIENT_SECRETS_FILE = "client_secrets.json"

# This OAuth 2.0 access scope allows for full read/write access to the
# authenticated user's account and requires requests to use an SSL connection.
YOUTUBE_READ_WRITE_SSL_SCOPE = "https://www.googleapis.com/auth/youtube.force-ssl"
YOUTUBE_API_SERVICE_NAME = "youtube"
YOUTUBE_API_VERSION = "v3"

# This variable defines a message to display if the CLIENT_SECRETS_FILE is
# missing.
MISSING_CLIENT_SECRETS_MESSAGE = """
WARNING: Please configure OAuth 2.0

To make this sample run you will need to populate the client_secrets.json file
found at:
   %s
with information from the APIs Console
https://console.developers.google.com

For more information about the client_secrets.json file format, please visit:
https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
""" % os.path.abspath(os.path.join(os.path.dirname(__file__),CLIENT_SECRETS_FILE))

# Authorize the request and store authorization credentials.
def get_authenticated_service(args):
  flow = flow_from_clientsecrets(CLIENT_SECRETS_FILE, scope=YOUTUBE_READ_WRITE_SSL_SCOPE,message=MISSING_CLIENT_SECRETS_MESSAGE)

  storage = Storage("%s-oauth2.json" % sys.argv[0])
  credentials = storage.get()

  if credentials is None or credentials.invalid:
    credentials = run_flow(flow, storage, args)

  # Trusted testers can download this discovery document from the developers page
  # and it should be in the same directory with the code.
  with open("youtube-v3-discoverydocument.json", "r") as f:
    doc = f.read()
    return build_from_document(doc, http=credentials.authorize(httplib2.Http()))


# Call the API's commentThreads.list method to list the existing comments.
def get_comments(youtube, video_id, channel_id):
  results = youtube.commentThreads().list(
    part="snippet",
    videoId=video_id,
    channelId=channel_id,
    # ONLY FILTER COMMENTS THAT ARE HELD FOR REVIEW
    # THOSE COMMENTS ONLY HAVE ONE TOP LEVEL COMMENT
    moderationStatus="heldForReview",
    textFormat="plainText").execute()

  for item in results["items"]:
    comment = item["snippet"]["topLevelComment"]
    author = comment["snippet"]["authorDisplayName"]
    text = comment["snippet"]["textDisplay"]
    print "Comment by %s: %s" % (author, text)

  return results["items"]


# Call the API's commentThreads.insert method to insert a comment.
def insert_comment(youtube, channel_id, video_id, text):
  insert_result = youtube.commentThreads().insert(
    part="snippet",
    body=dict(
      snippet=dict(
        channelId=channel_id,
        videoId=video_id,
        topLevelComment=dict(
          snippet=dict(
            textOriginal=text
          )
        )
      )
    )
  ).execute()

  comment = insert_result["snippet"]["topLevelComment"]
  author = comment["snippet"]["authorDisplayName"]
  text = comment["snippet"]["textDisplay"]
  print "Inserted comment for %s: %s" % (author, text)


# Call the API's commentThreads.update method to update an existing comment.
def update_comment(youtube, comment):
  comment["snippet"]["topLevelComment"]["snippet"]["textOriginal"] = 'updated'
  update_result = youtube.commentThreads().update(
    part="snippet",    
    body=comment
  ).execute()

  comment = update_result["snippet"]["topLevelComment"]
  author = comment["snippet"]["authorDisplayName"]
  text = comment["snippet"]["textDisplay"]
  print "Updated comment for %s: %s" % (author, text)


if __name__ == "__main__":
  # The "channelid" option specifies the YouTube channel ID that uniquely
  # identifies the channel for which the comment will be inserted.
  argparser.add_argument("--channelid",
    help="Required; ID for channel for which the comment will be inserted.")
  # The "videoid" option specifies the YouTube video ID that uniquely
  # identifies the video for which the comment will be inserted.
  argparser.add_argument("--videoid",
    help="Required; ID for video for which the comment will be inserted.")
  # The "text" option specifies the text that will be used as comment.
  argparser.add_argument("--text", help="Required; text that will be used as comment.")
  args = argparser.parse_args()

  if not args.channelid:
    exit("Please specify channelid using the --channelid= parameter.")
  if not args.videoid:
    exit("Please specify videoid using the --videoid= parameter.")
  if not args.text:
    exit("Please specify text using the --text= parameter.")

  youtube = get_authenticated_service(args)
  try:
    # All the available methods are used in sequence just for the sake of an example.
    # Insert channel comment by omitting videoId
    # REMOVED AS IT IS NOT RELEVANT TO THE ERRRO REPORT. insert_comment(youtube, args.channelid, None, args.text)
    # Insert video comment
    # REMOVED AS IT IS NOT RELEVANT TO THE ERRRO REPORT. insert_comment(youtube, args.channelid, args.videoid, args.text)
    video_comments = get_comments(youtube, args.videoid, None)
    if video_comments:
      update_comment(youtube, video_comments[0])

  except HttpError, e:
    print "An HTTP error %d occurred:\n%s" % (e.resp.status, e.content)
  else:
    print "Inserted, listed and updated top-level comments."

Of course, you will need your authorization files inside the same directory.

Alex Benfica
  • 408
  • 5
  • 17
  • Is there a question as part of this question. or are you just sharing an issue you created? – Linda Lawton - DaImTo Nov 09 '16 at 13:06
  • Hi DamlTo. Both. The question is: Is there any other way to respond to the top level comments without using this exactly API? – Alex Benfica Nov 09 '16 at 13:07
  • In that case for us to assist you in debugging your code you need to post your code. We don't need to see your issue request. Link to it if you like http://stackoverflow.com/help/mcve – Linda Lawton - DaImTo Nov 09 '16 at 13:09
  • The only way to update YouTube commentThreads programmatically is though https://developers.google.com/youtube/v3/docs/commentThreads/update – Linda Lawton - DaImTo Nov 09 '16 at 13:11
  • I thought that sharing the url to github would be the ideial. The code is this file: https://github.com/alexbenfica/commentThreads.update-bug-report/blob/master/python/comment_threads.py Exactly as it is. This is an example call that causes the error: python comment_threads.py --channelid=UCQzm6RcaOty8QU2VhHbRg-g --videoid=1AV4nTfIrts --text=Test You must use a channel you are authorized to and the video must have comments with moderation status "heldForReview". – Alex Benfica Nov 09 '16 at 13:14
  • links die after time its best to include the code in your question please read http://stackoverflow.com/help/how-to-ask and I wouldn't your github upload a MCVE either. – Linda Lawton - DaImTo Nov 09 '16 at 13:15
  • Ok. You are right. Should I erase this question and create a new one? – Alex Benfica Nov 09 '16 at 13:32
  • 1
    or just edit it is fine. – Linda Lawton - DaImTo Nov 09 '16 at 13:45
  • Well, make sure you are authorized to make this call. From the [documentation](https://developers.google.com/youtube/v3/docs/commentThreads/list#moderationStatus), it is stated here that `moderationStatus` parameter can only be used in a properly [authorized request](https://developers.google.com/youtube/v3/guides/authentication). Set this parameter to limit the returned comment threads to a particular moderation state. Try to use your own videoId [here](https://developers.google.com/youtube/v3/docs/commentThreads/list) in the **"try it part"** and check if you still get the 400 error code. – KENdi Nov 10 '16 at 08:42
  • I am using my own channel and my own video and an authorized request. This same script was working fine since it was created in the last year or more, and just stopped to work some days ago. The error also happens using the API explorer. Did you try it? – Alex Benfica Nov 10 '16 at 08:59
  • Seems that this is relly an API issue, as I cannot reply or moderate comments using Hootsuite! Already informed them! Any ideias on how I can proceed to have it fixed? – Alex Benfica Nov 10 '16 at 12:19
  • This is happening right now for me with a JS script that was running fine until now. Even on the API page, a simple request for commentsThread is giving this error: https://developers.google.com/youtube/v3/docs/commentThreads/list#usage I believe the issue is **`this can be a transient error`** – brasofilo Jun 26 '18 at 22:23
  • Related and possible duplicates: [YouTube API v3.0 CommentsThread.list proccessing failuer issue](https://stackoverflow.com/q/39330599/1287812) | [YouTube v3 API returns status code 400 for a valid request](https://stackoverflow.com/q/30399526/1287812) | [Can't get all comments from Youtube Data API V3 \[Python\]](https://stackoverflow.com/q/48454296/1287812) – brasofilo Jun 26 '18 at 22:27
  • 1
    Yes, definetely a transient error, my script works again – brasofilo Jun 27 '18 at 11:15

0 Answers0