GoogleChrome/lighthouse · error · Error

Error: ${JSON.stringify(json)}

Error message

Error: ${JSON.stringify(json)}

What it means

Thrown by GithubApi.createGist when the GitHub API POST /gists response parsed as JSON does not contain an 'id' field. A successful gist creation returns the gist id; any response lacking it is treated as a failure and the whole response body is stringified into the error message for diagnosis. A 401 response additionally triggers sign-out before this throw is reached.

Source

Thrown at viewer/app/src/github-api.js:82

          },
        },
      };
      const request = new Request('https://api.github.com/gists', {
        method: 'POST',
        headers: new Headers({Authorization: `token ${accessToken}`}),
        // Stringify twice so quotes are escaped for POST request to succeed.
        body: JSON.stringify(body),
      });
      const response = await fetch(request);
      if (response.status === 401) {
        this._auth.signOut();
      }
      const json = await response.json();
      if (json.id) {
        logger.log('Saved!');
        return json.id;
      } else {
        throw new Error('Error: ' + JSON.stringify(json));
      }
    } finally {
      this._saving = false;
    }
  }

  /**
   * Fetches a Lighthouse report from a gist.
   * @param {string} id The id of a gist.
   * @return {Promise<LH.Result>}
   */
  getGistFileContentAsJson(id) {
    logger.log('Fetching report from GitHub...', false);

    return this._auth.getAccessTokenIfLoggedIn().then(accessToken => {
      const headers = new Headers();

      // If there's an authenticated token, include an Authorization header to

View on GitHub (pinned to 9515cd4e58)

Solutions

  1. Inspect the stringified JSON in the error message — it typically states the problem (e.g. 'rate limit', 'Validation Failed').
  2. If rate-limited, wait and retry; ensure the access token has the 'gist' scope.
  3. Wrap createGist in try/catch and show the parsed GitHub message to the user.

Example fix

// before
const id = await githubApi.createGist(json); // unhandled on API error

// after
try {
  const id = await githubApi.createGist(json);
} catch (err) {
  const apiMsg = err.message; // contains JSON.stringify(githubResponse)
  showUserError(`Could not save gist: ${apiMsg}`);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// No pre-call validation possible (server decides); validate the token scope instead.
const token = await auth.getAccessToken();
// Tokens must have the 'gist' scope; verify out-of-band before saving.

Try / catch

try {
  const id = await githubApi.createGist(json);
} catch (err) {
  // err.message is 'Error: ' + JSON.stringify(githubResponse)
  const apiError = (() => { try { return JSON.parse(err.message.replace(/^Error:\s*/, '')); } catch { return null; } })();
  showUserError(apiError?.message ? `GitHub: ${apiError.message}` : err.message);
}

Prevention

When it happens

Trigger: GitHub returns an error payload (rate-limit message, validation error, 422 unprocessable entity, permission error) instead of a gist object, so json.id is undefined.

Common situations: GitHub API rate limiting (secondary rate limits return JSON errors with HTTP 200/403); token lacking gist scope; gist content too large; transient GitHub API error responses.

Related errors


AI-assisted analysis of GoogleChrome/lighthouse@9515cd4e58 (2026-08-13). Data as JSON: /api/errors/49bc1b77c1642319. Report an issue: GitHub.