badges/shields · error · InvalidResponse

undecodable content

Error message

undecodable content

What it means

fetchRepoContent() decodes GitHub's base64-encoded file content to UTF-8 and wraps any decoding failure in InvalidResponse 'undecodable content'. It is thrown when Buffer.from(content, 'base64')/toString produces or receives data that cannot be handled, meaning the repository file content isn't valid base64 or the expected shape changed. Treat it as an upstream data problem, not a bug in your request parameters.

Source

Thrown at services/github/github-common-fetch.js:43

async function fetchRepoContent(
  serviceInstance,
  { user, repo, branch = 'HEAD', filename },
) {
  const httpErrors = httpErrorsFor(
    `repo not found, branch not found, or ${filename} missing`,
  )
  if (serviceInstance.staticAuthConfigured) {
    const { content } = await serviceInstance._requestJson({
      schema: contentSchema,
      url: `/repos/${user}/${repo}/contents/${filename}`,
      options: { searchParams: { ref: branch } },
      httpErrors,
    })

    try {
      return Buffer.from(content, 'base64').toString('utf-8')
    } catch (e) {
      throw new InvalidResponse({ prettyMessage: 'undecodable content' })
    }
  } else {
    const { buffer } = await serviceInstance._request({
      url: `https://raw.githubusercontent.com/${user}/${repo}/${branch}/${filename}`,
      httpErrors,
    })
    return buffer
  }
}

async function fetchJsonFromRepo(
  serviceInstance,
  { schema, user, repo, branch = 'HEAD', filename },
) {
  if (serviceInstance.staticAuthConfigured) {
    const buffer = await fetchRepoContent(serviceInstance, {
      user,
      repo,

View on GitHub (pinned to 766fd8bc89)

Solutions

  1. Confirm the target file is under 1MB, or use the raw.githubusercontent.com / Git blobs API for large files.
  2. Retry the request — transient API issues can return incomplete payloads.
  3. Check that the requested file exists and is a regular text file, not a submodule, symlink, or directory listing.

Example fix

// before: fetching a 2MB config through the contents API
/service/github/user/repo/config/large-config.json
// after: keep tracked config files under 1MB or use raw content
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check file size via the contents API metadata
const meta = await fetch('https://api.github.com/repos/OWNER/REPO/contents/' + path).then(r => r.json());
if (meta.size > 1000000) throw new Error('file too large for base64 contents API');

Type guard

function isDecodableContent(content) {
  return typeof content === 'string' && content.length > 0 && /^[A-Za-z0-9+/=\s]+$/.test(content);
}

Try / catch

try {
  const text = await fetchRepoContent({ user, repo, filename, branch });
} catch (e) {
  if (e.prettyMessage === 'undecodable content') {
    // fall back to raw.githubusercontent.com or the git blobs API
  } else throw e;
}

Prevention

When it happens

Trigger: Requesting a file's content through the GitHub contents API (GraphQL or REST path used by configContent/buffer/content) where the returned `content` field is not valid base64 — e.g. file larger than 1MB so GitHub returns content: null, an empty string, or a malformed payload.

Common situations: Pointing the service at a file >1MB (contents API truncates/omits base64 content); binary files fetched via a route expecting base64 JSON; GitHub API response shape changes; requesting a file that is actually a Git LFS pointer in an unexpected path.

Related errors


AI-assisted analysis of badges/shields@766fd8bc89 (2026-08-30). Data as JSON: /api/errors/7dd01d950471845e. Report an issue: GitHub.