decolua/9router · error · Error
Zed credential is missing userId or accessToken
Error message
Zed credential is missing userId or accessToken
What it means
buildZedUserAuthHeader builds the Zed `Authorization: "<userId> <accessToken>"` header from credentials. It reads userId from providerSpecificData.userId or credentials.userId, and the token from credentials.accessToken or credentials.apiKey. If either is absent it throws, since Zed's user-auth endpoints cannot be called without both parts.
Source
Thrown at open-sse/shared/zedAuth.js:164
return crypto
.privateDecrypt(
{ key: privateKey, padding: crypto.constants.RSA_PKCS1_PADDING },
encrypted,
)
.toString("utf8");
} catch {
const message = oaepError instanceof Error ? oaepError.message : String(oaepError);
throw new Error(`Failed to decrypt Zed access token: ${message}`);
}
}
}
export function buildZedUserAuthHeader(credentials) {
const psd = credentials?.providerSpecificData || {};
const userId = psd.userId || credentials?.userId;
const accessToken = credentials?.accessToken || credentials?.apiKey;
if (!userId || !accessToken) {
throw new Error("Zed credential is missing userId or accessToken");
}
return `${userId} ${accessToken}`;
}
function getSystemId(credentials) {
return String(
credentials?.providerSpecificData?.systemId || credentials?.systemId || "",
);
}
async function fetchJson(url, options, proxyOptions = null) {
const res = await proxyAwareFetch(url, options, proxyOptions);
const text = await res.text();
let data = null;
if (text) {
try {
data = JSON.parse(text);
} catch {View on GitHub (pinned to 90b52e06ff)
Solutions
- Complete the Zed OAuth sign-in so the credential stores userId (in providerSpecificData or top-level) and accessToken.
- Check credentials.providerSpecificData.userId and credentials.accessToken directly before calling; fill in whatever is missing.
- If you have an apiKey instead of an OAuth token, ensure it is set on credentials.accessToken or credentials.apiKey — the header builder accepts apiKey as the token.
- Re-save the credential in the dashboard to make sure partial data wasn't persisted.
Example fix
// before
buildZedUserAuthHeader({ accessToken: "tok" }); // no userId
// after
buildZedUserAuthHeader({ providerSpecificData: { userId: "42" }, accessToken: "tok" }); Defensive patterns
Strategy: validation
Validate before calling
function canBuildZedHeader(cred) {
const psd = cred?.providerSpecificData || {};
return Boolean((psd.userId || cred?.userId) && (cred?.accessToken || cred?.apiKey));
}
// guard: if (!canBuildZedHeader(credentials)) prompt OAuth sign-in before any Zed API call;
Type guard
const hasZedCredential = (c) => Boolean(c && (c.providerSpecificData?.userId || c.userId) && (c.accessToken || c.apiKey));
Try / catch
let authHeader;
try {
authHeader = buildZedUserAuthHeader(credentials);
} catch (e) {
// credential incomplete — kick off Zed OAuth sign-in flow to fill userId/accessToken
} Prevention
- Require the OAuth callback step to complete before saving a Zed provider credential.
- Validate credentials on save (both userId and accessToken present).
- Don't import/sync partial Zed credentials; carry providerSpecificData.userId along.
When it happens
Trigger: Calling fetchZedAuthenticatedUser/fetchZedLlmToken with a credentials object that lacks userId or accessToken/apiKey — e.g. an API-key-only credential that never went through the Zed OAuth callback, or a partially-saved credential row.
Common situations: User added a Zed provider with only an API key (no OAuth sign-in); credential sync/import dropped providerSpecificData.userId; the decrypt step failed earlier so accessToken was never persisted.
Related errors
- ${provider} API key required
- cosy: user id is empty
- Missing Zed callback URL
- Zed models failed: ${response.status} ${text}
- No active credentials for provider: ${provider}
AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30).
Data as JSON: /api/errors/6bfe174491307301.
Report an issue: GitHub.