decolua/9router · error · Error

cosy: user id is empty

Error message

cosy: user id is empty

What it means

buildCosyHeaders signs every Cosy/Qoder request with credentials that must include a userId. The function throws immediately when creds.userId is missing or empty, before computing the encrypted header payload. This is a credential-completeness guard: signed requests cannot be constructed without a user identity.

Source

Thrown at open-sse/shared/qoder/cosy.js:117

  return uuidv4();
}

/**
 * Build the full Cosy-* header set for a single Qoder request.
 *
 * @param {Buffer|Uint8Array|string} body  The exact bytes that will be sent.
 *   For GET requests pass an empty Buffer / "".
 * @param {string} requestUrl              Full request URL (used for sigPath).
 * @param {object} creds
 * @param {string} creds.userId            Stable Qoder user id.
 * @param {string} creds.authToken         Device access token (`dt-...`).
 * @param {string} [creds.name]            Display name (optional).
 * @param {string} [creds.email]           Email (optional, can be empty).
 * @param {string} [creds.machineId]       Persisted machine UUID.
 * @returns {Record<string, string>} Header map ready to merge onto fetch().
 */
export function buildCosyHeaders(body, requestUrl, creds) {
  if (!creds?.userId) throw new Error("cosy: user id is empty");
  if (!creds?.authToken) throw new Error("cosy: auth token is empty");

  const bodyBuf = Buffer.isBuffer(body)
    ? body
    : typeof body === "string"
      ? Buffer.from(body, "latin1")
      : Buffer.from(body || []);

  const { cosyKey, info } = encryptUserInfo({
    uid: creds.userId,
    security_oauth_token: creds.authToken,
    name: creds.name || "",
    aid: "",
    email: creds.email || "",
  });

  const timestamp = String(Math.floor(Date.now() / 1000));
  const requestId = uuidv4();

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Complete the Cosy login flow so both userId and authToken are persisted on the account
  2. Inspect the stored account record and backfill the missing userId
  3. Re-authenticate the Qoder/Cosy provider from the dashboard to rewrite credentials
  4. Check field naming — ensure the code reads creds.userId and the storage layer uses the same key

Example fix

// before
const headers = buildCosyHeaders(body, url, { authToken: account.token });
// after
const headers = buildCosyHeaders(body, url, { authToken: account.token, userId: account.userId });
Defensive patterns

Strategy: validation

Validate before calling

function canBuildCosyHeaders(creds) {
  return Boolean(creds?.userId && creds?.authToken);
}
if (!canBuildCosyHeaders(creds)) await ensureCosyLogin(account);

Type guard

function hasCosyUserId(c) { return typeof c?.userId === "string" && c.userId.length > 0; }

Try / catch

try {
  headers = buildCosyHeaders(body, url, creds);
} catch (e) {
  if (/user id is empty/.test(e.message)) {
    await reloginCosy(account);
    headers = buildCosyHeaders(body, url, refreshedCreds);
  } else throw e;
}

Prevention

When it happens

Trigger: Executing a Cosy request (via execute or headers helpers) with creds = { authToken: '...' } but no userId, or userId = '' after a partial login/parse of the account record.

Common situations: OAuth/login flow stored the authToken but failed to persist userId; account imported by pasting only a token; DB record fields renamed so userId is read from the wrong key; migration dropping the column.

Related errors


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/cf486bd2e2870249. Report an issue: GitHub.