different-ai/openwork · error · Error
Profile update response did not include a user.
Error message
Profile update response did not include a user.
What it means
updateProfile in DenFlowProvider calls the Den API to update the user's profile and expects the response body to contain a user object extractable via getUser(payload). If the HTTP call succeeds but the payload lacks a recognizable user shape, this error is thrown so the app never sets an undefined user into context. It indicates an API contract mismatch between client and server.
Solutions
- Inspect the actual response payload in devtools/network tab and compare with what getUser(payload) expects (field name and shape).
- Check that the den-web client and den server versions match; redeploy whichever is stale.
- If the server intentionally returns an envelope, update getUser in the provider to unwrap it.
- Add a server-side fix to always return the full user object on profile update.
Example fix
// before
const nextUser = getUser(payload);
if (!nextUser) throw new Error("Profile update response did not include a user.");
// after
const rawUser = payload?.user ?? payload?.data?.user;
const nextUser = rawUser ? getUser({ user: rawUser }) : undefined;
if (!nextUser) throw new Error("Profile update response did not include a user."); Defensive patterns
Strategy: validation
Validate before calling
function hasUser(p: unknown): boolean {
return typeof p === "object" && p !== null && "user" in p && typeof (p as {user:unknown}).user === "object";
}
if (!hasUser(payload)) { /* don't call updateProfile-dependent UI */ } Type guard
function isUser(u: unknown): u is { id: string; email: string } {
return typeof u === "object" && u !== null && "id" in u && "email" in u;
} Try / catch
try {
await updateProfile(data);
} catch (err) {
if (err instanceof Error && err.message.includes("did not include a user")) {
showToast("Profile saved but response was malformed — reloading.");
await refetchUser();
} else throw err;
} Prevention
- Keep client getUser() in sync with the server's profile-update response schema.
- Add a Zod schema over the update response and test it in CI against the real endpoint shape.
- Pin and deploy client and server together so contract changes land atomically.
- Log raw payloads on this error to speed up contract-mismatch diagnosis.
When it happens
Trigger: The PUT/PATCH profile endpoint returns 2xx with an empty body, a wrapped envelope like {data:{...}} instead of {user:{...}} (or whatever getUser expects), or a partial-update response that only returns the changed fields.
Common situations: Server deployed at a different version than the web client after an API contract change; a proxy stripping or reshaping the response; hitting a mock/stub endpoint that returns {} with 200.
Understand the failure class
Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.
Related errors
- Automation run history was invalid.
- Connection details were missing from the worker response.
- The plugin was created, but no id was returned.
- API key was created, but the secret was not returned.
- Automation cancellation response was invalid.
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/63924a31864c8f16.
Report an issue: GitHub.
Appendix: source
Thrown at ee/apps/den-web/app/(den)/_providers/den-flow-provider.tsx:1425
}
async function updateUserProfile(input: { firstName: string; lastName: string }) {
const { response, payload } = await requestJson(
"/v1/me/profile",
{
method: "PATCH",
body: JSON.stringify(input),
},
12000,
);
if (!response.ok) {
throw new Error(getErrorMessage(payload, `Failed to update profile (${response.status}).`));
}
const nextUser = getUser(payload);
if (!nextUser) {
throw new Error("Profile update response did not include a user.");
}
setUser(nextUser);
identifyPosthogUser(nextUser);
return nextUser;
}
async function launchWorker(options: { source?: "manual" | "signup_auto"; workerNameOverride?: string } = {}) {
if (!user) {
setAuthError("Sign in before launching a worker.");
return "error" as const;
}
const resolvedLaunchName = options.workerNameOverride?.trim() || workerName.trim() || DEFAULT_WORKER_NAME;
setLaunchBusy(true);
setLaunchError(null);
setOrgLimitError(null);View on GitHub (pinned to 2b7df46e8a)