gildas-lormeau/SingleFile · error · Error

response.error

Error message

response.error

What it means

getJSON first validates the HTTP status via getResponse, then parses the JSON body; if the parsed body contains an `error` property, it throws that value as an Error. This surfaces Google Drive API structured error objects (e.g. {error: {code, message, errors: [...]}}) directly to the caller, so the thrown Error may not be a plain string message.

Source

Thrown at src/lib/gdrive/gdrive.js:477

		const range = httpResponse.headers.get("Range");
		if (range) {
			mediaUploader.offset = parseInt(range.match(/\d+/g).pop(), 10) + 1;
		}
		if (mediaUploader.cancelled) {
			throw new Error("upload_cancelled");
		} else {
			return sendFile(mediaUploader);
		}
	} else {
		getResponse(httpResponse);
	}
}

async function getJSON(httpResponse) {
	httpResponse = getResponse(httpResponse);
	const response = await httpResponse.json();
	if (response.error) {
		throw new Error(response.error);
	} else {
		return response;
	}
}

function getResponse(httpResponse) {
	if (httpResponse.status == 200) {
		return httpResponse;
	} else if (httpResponse.status == 404) {
		throw new Error("path_not_found");
	} else if (httpResponse.status == 401) {
		throw new Error("invalid_token");
	} else {
		throw new Error("unknown_error (" + httpResponse.status + ")");
	}
}

View on GitHub (pinned to 517fb7c5cf)

Solutions

  1. Log/serialize the thrown error's message as JSON (response.error may be an object) to see code, message, and errors[].
  2. Check the embedded error.errors[].reason for rate limiting and retry with exponential backoff if it is rateLimited/userRateLimitExceeded.
  3. Verify the OAuth token's scopes cover the requested operation.
  4. Confirm the endpoint URL and API version are current for the Drive v3 API.

Example fix

// before
catch (e) { console.error(e.message); } // prints [object Object]
// after
catch (e) {
  const detail = typeof e.message === "string" ? e.message : JSON.stringify(e.message);
  console.error("Drive API error:", detail);
}
Defensive patterns

Strategy: type-guard

Type guard

function isDriveErrorPayload(m) {
  return m !== null && typeof m === "object" &&
    ((typeof m.code === "number") || Array.isArray(m.errors) || typeof m.message === "string");
}
// usage
catch (e) { if (isDriveErrorPayload(e.message)) { handleDriveApiError(e.message); } else throw e; }

Try / catch

try { const data = await gdrive.getJSON(resp); }
catch (e) {
  const payload = typeof e.message === "string" ? { message: e.message } : e.message;
  if (payload && payload.errors && payload.errors[0] && payload.errors[0].reason === "rateLimitExceeded") {
    return retryWithBackoff();
  }
  throw e;
}

Prevention

When it happens

Trigger: Any call whose HTTP response is 2xx/acceptable but whose JSON body carries an error field — e.g. a Drive API error returned with an unexpected status that getResponse let through, or an endpoint returning 200 with an embedded error object.

Common situations: Drive API rate-limit or userRateLimitExceeded errors wrapped in JSON; malformed OAuth scopes producing an error body; API version changes that move error information into the body; catching the error and assuming message is a string when it is an object.

Related errors


AI-assisted analysis of gildas-lormeau/SingleFile@517fb7c5cf (2026-09-01). Data as JSON: /api/errors/506b2ee3fec61fec. Report an issue: GitHub.