You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I am in a new profile and am trying to addd a first project webID(https://solidos.solidcommunity.net/profile/card#me) and I get a big fat error. I am logged in.
I tried logout and login again. I can edit other parts like resume but not this.
debug.ts:12 Projects mutation save failed Error: Exception in update: Error: Update: Can't make changes in uneditable <https://timea2.pivot-test.solidproject.org:3000/profile/card> Error: Update: Can't make changes in uneditable <https://timea2.pivot-test.solidproject.org:3000/profile/card> undefined Error: Update: Can't make changes in uneditable <https://timea2.pivot-test.solidproject.org:3000/profile/card> undefined at :3000/profile/Update…:15) undefined:0:0 at :3000/mashlib.js:138838:9 undefined:0:0 at new :3000/profile/Promis…us>) undefined:0:0 at :3000/profile/rdfMut…:10) undefined:0:0 at :3000/profile/rdfMut…:11) undefined:0:0 at :3000/profile/projec…:11) undefined:0:0 at :3000/profile/projec…:11) undefined:0:0 at :3000/profile/Object…:15) undefined:0:0 at :3000/profile/Object…:53) undefined:0:0 at async s.<anonymous> (dialog.ts:410:16) at rdfMutationHelpers.ts:256:20 at rdfMutationHelpers.ts:251:15 at new Promise (<anonymous>) at rdfMutationHelpers_esm_C (rdfMutationHelpers.ts:249:10) at rdfMutationHelpers_esm_T (rdfMutationHelpers.ts:379:11) at projects_mutations_esm_m (mutations.ts:175:9) at projects_mutations_esm_h (mutations.ts:186:9) at Object.onSave (ProjectEditDialog.ts:186:13) at Object.beforeClose (dialog.ts:563:27)
After lots of investigation I realized this problem is specific to the restore Session not a fresh login. What's happening is that when the resources are first fetched, they are fetched anonymously and when the "restored login" comes through it does not refresh the resources so they are authenticated. This affects whether we can PATCH the resource versus PUT a completely new one. RDFLIB checks whether a resource is edittable before it does a PATCH, but for PUT it doesn't. The failure we are seeing is the edittable check like you mentioned. The user is logged in so of course when it does the PUT it works without a problem. It's important that it checks the editable for PATCH because there is information in the metadata that tells you how to PATCH (from Tim)
This problem was further complicated by the fact that you can't just refresh an already fetched resource because it has a check for that and the data that existed made it fail this check. Because of this we had to remove the resource/resources so it/they can be refreshed with authentication. As well the session restore event was not being emitted due to a timeout.
Note: The legacy EditProfileView checks this status before it will display the editor at all, so the user would get the message and have to relogin in order to see/use the editor.
Previous History
I am pretty sure we ran into this problem previously, definitely we had some inconsistencies in what was happening. I remember them and the mutation code kept evolving because of it. This is one reason it's only a problem with projects, skills, heading and bio. Resume, contact info, social and languages are okay.
The other sections already leaned to PUT instead of PATCH for some different reasons. One is that I added the prefixes, so if a profile document does not have prefixes it will add them when it writes/changes data and that requires a PUT. Also, I think because of inconsistencies I ended up having to add in logic for checks to forcePut and also a fallback to PUT if PATCH didn't work. I'm still slightly confused as to why the fallback wasn't working for these 2 sections, it basically wasn't an exact match for the error check that then decides to use PUT.
We already have a ticket for reviewing/redoing the mutations. I think this would be another reason to, because I think we really should be using PATCH not falling back to a PUT. I think we should only PUT if we want to add the prefixes. But this is just an opinion/gut feel. I would like to discuss it further in a meeting to see what is the best protocol for this. The legacy edit profile only uses PATCH.
I am not sure about the friend's page yet. I will have a look at that soon.
@SharonStrats@NoelDeMartin
After the merged SolidOS/solid-logic#326 I went to re-analyse the issue and where it should come from.
The PR was of high help.
The issue is that the UVDSL solid logic do not take enough account of the authentication being valid across browser tab's/reload
The point 1. is just factual at this stage.
The analysis was made across rdflib, solid-logic, solid-ui and solid-panes
Resumé: the editable-refresh work
Why the merged solution is incomplete
The merged PR #326 (commit 3c06085) added checkAndRefreshEditable() to solid-logic/src/resource/resourceLogic.ts: sync editable() → if false/undefined, fetcher.refresh(doc) → re-check. What it does not do:
Nobody calls it. In all four repos (staging), it has no callers — only its definition, the type, and one mocked test. Nothing changes behavior yet.
Wrong layer. It repairs one resource when asked. The problem is store-wide: every recorded response is stale after an identity change, and ~35 other sync editable() call sites keep returning the old wrong answer until each doc happens to be loaded.
Incomplete lifecycle. It doesn't cover the cases that actually hurt: session restore (the race), logout (stale "editable" → failed writes), identity change, cross-tab.
Unproven core. Its unit test mocks editable/refresh; only a real-server test can prove the refresh rewrites the metadata editable() reads. And it refreshes even on genuinely false, costing a request per read-only check.
Duplicates rdflib.UpdateManager.checkEditable() already does the unknown→load→re-answer cycle (since v2.2.31).
The root cause (one paragraph)
editable() is a synchronous read of cached HTTP metadata under fetcher.appNode, keyed by document but not by identity. Responses recorded anonymously (before restore completes) or under a previous WebID stay definitive after the session changes. Nothing invalidates them on transitions. rdflib has the intended fix — flagAuthorizationMetadata() (mark all recorded responses outOfDate; its comment describes exactly this login case) plus checkEditable() (unknown → load → re-answer) — and fetcher.load() cooperates by clearing the flag and force-refetching. solid-ui calls the flag only in its login-button paths; solid-logic, which now owns the session lifecycle, never calls it. Cross-tab transitions do arrive (SharedWorker → TOKEN_DETAILS → in-page sessionStateChange), but explicit login/logout in another tab is not broadcast.
What has to be done
1. solid-logic — the root fix (small):
Call store.updater.flagAuthorizationMetadata() on every identity transition: after restore() becomes active (sessionRestore), after handleRedirectFromLogin() (login), on logout (active→inactive), on identity change while active (extend the sessionStateChange listener to compare the last WebID), and as a cross-tab safety net: on tab focus, if session.webId changed since the last flag. Hook point: where store and session meet (createSolidLogic subscribing to authSession.events, or passing the store to SolidAuthnLogic).
2. solid-ui + solid-panes — the decision points (mechanical, wide):
Convert gating sync checks to await updater.checkEditable(...) (it loads only when unknown; load-before-check also self-heals). Priority order:
solid-ui/widgets/forms.js (13 sites) + widgets/forms/basic.ts — the main editing surface;
cosmetic sites (internalPane, trustedApplications, preferences.js) can stay;
solid-logic/utilityLogic.ts is already safe (awaits load first).
3. rdflib — nothing required. Methods exist and are the right shape. Do not put the load inside sync editable() (can't await; fire-and-forget would fan out fetches for every displayed doc) and do not evict/remove the store (doesn't change the verdict — metadata isn't in the doc — and destroys unsaved edits, pane references, and patch bookkeeping).
4. Tests — what "done" means:
Unit: false-recorded response → flag → editable() undefined → checkEditable loads → true with fresh response.
E2E on a real CSS: log out → load doc → log in → editable true and a PATCH succeeds; same for reload/restore; logout stops offering edit; cross-tab login (login in B, focus A) yields correct state.
Sequencing: step 1 first — it fixes the common flows on its own because opening a resource loads it (self-heal). Then forms. The merged helper becomes an optional cold-path fallback, not the mechanism.
Thanks Alain. I had trouble with knowing exactly where to place the call. I have a couple closed PRs because of it :). I'll let Noel chime in before changing anything because he had an opinion of where it should be placed. I ended up adding the flag metadata call here SolidOS/solid-ui#870 for session Restore only. Although as a side note it is also called for login here. (Note: I've written it in another PR, but it is also called in a logout eventlistener in the old legacy login/login.ts in solid-ui.)
The function in solid-logic I call here SolidOS/profile-pane#465 to fix this issue here in this ticket, but I thought we'd have to call it anywhere we need to PATCH, that's why I put it in solid-logic. Nice to know that it self heals, I did not realize that. I tried so many things I lost track of retrying things.
Once we hear from Noel I can revert my changes and in the profile-pane just call editable check.
@bourgeoa thank you! What you mention makes sense and I think making a PR would be great. Before merge let's just see what @NoelDeMartin has to say, because I had a PR adding it to solid-logic (although not in the best way) and he didn't approve. But what you say here, I think it makes a lot of sense.
I'll take care of the changes to revert the solid-logic function, remove the listener in solid-ui that I added, and change profile-pane to only call check Editable not the solid-logic function.
We can create a ticket for the other known places you listed to do the checkeditable and I can do them at some point. Lets discuss how soon we should do it on Wednesday.
Hey, the only reason I rejected those PRs is that the code was implemented as a side-effect, which should be avoided for tree-shaking and unintended side-effects when importing functions, etc. As long as the code is not implemented like that, I'd probably be ok with it.
Activity
timea-solid commentedon Aug 31, 2026
Update: It seems I had the same issue on editing skills too.
timea-solid commentedon Aug 31, 2026
This seems to mee a missing check of editable or maybe it looses being editable or something...
timea-solid commentedon Aug 31, 2026
Maybe also related: I am in preferences and I have an editable error too:
Maybe there is a session problem... maybe we loose being logged in info?! Further testing is necessary.
[-]Add project and Communities - cannot add a new webID[/-][+]Non editable profile - even if loggedin[/+]timea-solid commentedon Aug 31, 2026
I also saw this on a friend's page.. I was logged in but the drag and drop did not appear. It is like it lost the info that I am still logged in.
SharonStrats commentedon Sep 8, 2026
After lots of investigation I realized this problem is specific to the restore Session not a fresh login. What's happening is that when the resources are first fetched, they are fetched anonymously and when the "restored login" comes through it does not refresh the resources so they are authenticated. This affects whether we can PATCH the resource versus PUT a completely new one. RDFLIB checks whether a resource is edittable before it does a PATCH, but for PUT it doesn't. The failure we are seeing is the edittable check like you mentioned. The user is logged in so of course when it does the PUT it works without a problem. It's important that it checks the editable for PATCH because there is information in the metadata that tells you how to PATCH (from Tim)
This problem was further complicated by the fact that you can't just refresh an already fetched resource because it has a check for that and the data that existed made it fail this check. Because of this we had to remove the resource/resources so it/they can be refreshed with authentication. As well the session restore event was not being emitted due to a timeout.
Note: The legacy EditProfileView checks this status before it will display the editor at all, so the user would get the message and have to relogin in order to see/use the editor.
Previous History
I am pretty sure we ran into this problem previously, definitely we had some inconsistencies in what was happening. I remember them and the mutation code kept evolving because of it. This is one reason it's only a problem with projects, skills, heading and bio. Resume, contact info, social and languages are okay.
The other sections already leaned to PUT instead of PATCH for some different reasons. One is that I added the prefixes, so if a profile document does not have prefixes it will add them when it writes/changes data and that requires a PUT. Also, I think because of inconsistencies I ended up having to add in logic for checks to forcePut and also a fallback to PUT if PATCH didn't work. I'm still slightly confused as to why the fallback wasn't working for these 2 sections, it basically wasn't an exact match for the error check that then decides to use PUT.
We already have a ticket for reviewing/redoing the mutations. I think this would be another reason to, because I think we really should be using PATCH not falling back to a PUT. I think we should only PUT if we want to add the prefixes. But this is just an opinion/gut feel. I would like to discuss it further in a meeting to see what is the best protocol for this. The legacy edit profile only uses PATCH.
I am not sure about the friend's page yet. I will have a look at that soon.
Two fixes:
SolidOS/solid-logic#325
SolidOS/profile-pane#449
bourgeoa commentedon Sep 14, 2026
@SharonStrats @NoelDeMartin
After the merged SolidOS/solid-logic#326 I went to re-analyse the issue and where it should come from.
The PR was of high help.
The issue is that the UVDSL solid logic do not take enough account of the authentication being valid across browser tab's/reload
The point 1. is just factual at this stage.
The analysis was made across rdflib, solid-logic, solid-ui and solid-panes
Resumé: the editable-refresh work
Why the merged solution is incomplete
The merged PR #326 (commit
3c06085) addedcheckAndRefreshEditable()tosolid-logic/src/resource/resourceLogic.ts: synceditable()→ if false/undefined,fetcher.refresh(doc)→ re-check. What it does not do:editable()call sites keep returning the old wrong answer until each doc happens to be loaded.editable/refresh; only a real-server test can prove the refresh rewrites the metadataeditable()reads. And it refreshes even on genuinelyfalse, costing a request per read-only check.UpdateManager.checkEditable()already does the unknown→load→re-answer cycle (since v2.2.31).The root cause (one paragraph)
editable()is a synchronous read of cached HTTP metadata underfetcher.appNode, keyed by document but not by identity. Responses recorded anonymously (before restore completes) or under a previous WebID stay definitive after the session changes. Nothing invalidates them on transitions. rdflib has the intended fix —flagAuthorizationMetadata()(mark all recorded responsesoutOfDate; its comment describes exactly this login case) pluscheckEditable()(unknown → load → re-answer) — andfetcher.load()cooperates by clearing the flag and force-refetching. solid-ui calls the flag only in its login-button paths; solid-logic, which now owns the session lifecycle, never calls it. Cross-tab transitions do arrive (SharedWorker →TOKEN_DETAILS→ in-pagesessionStateChange), but explicit login/logout in another tab is not broadcast.What has to be done
1. solid-logic — the root fix (small):
Call
store.updater.flagAuthorizationMetadata()on every identity transition: afterrestore()becomes active (sessionRestore), afterhandleRedirectFromLogin()(login), onlogout(active→inactive), on identity change while active (extend thesessionStateChangelistener to compare the last WebID), and as a cross-tab safety net: on tab focus, ifsession.webIdchanged since the last flag. Hook point: where store and session meet (createSolidLogicsubscribing toauthSession.events, or passing the store toSolidAuthnLogic).2. solid-ui + solid-panes — the decision points (mechanical, wide):
Convert gating sync checks to
await updater.checkEditable(...)(it loads only when unknown;load-before-check also self-heals). Priority order:solid-ui/widgets/forms.js(13 sites) +widgets/forms/basic.ts— the main editing surface;solid-panes:form/pane.ts,outline/manager.js,ui/pane.js,defaultPane.ts,attachPane.js,schedulePane— affordances;internalPane,trustedApplications,preferences.js) can stay;solid-logic/utilityLogic.tsis already safe (awaitsloadfirst).3. rdflib — nothing required. Methods exist and are the right shape. Do not put the load inside sync
editable()(can't await; fire-and-forget would fan out fetches for every displayed doc) and do not evict/remove the store (doesn't change the verdict — metadata isn't in the doc — and destroys unsaved edits, pane references, and patch bookkeeping).4. Tests — what "done" means:
editable()undefined →checkEditableloads → true with fresh response.Sequencing: step 1 first — it fixes the common flows on its own because opening a resource loads it (self-heal). Then forms. The merged helper becomes an optional cold-path fallback, not the mechanism.
SharonStrats commentedon Sep 14, 2026
Thanks Alain. I had trouble with knowing exactly where to place the call. I have a couple closed PRs because of it :). I'll let Noel chime in before changing anything because he had an opinion of where it should be placed. I ended up adding the flag metadata call here SolidOS/solid-ui#870 for session Restore only. Although as a side note it is also called for login here. (Note: I've written it in another PR, but it is also called in a logout eventlistener in the old legacy login/login.ts in solid-ui.)
The function in solid-logic I call here SolidOS/profile-pane#465 to fix this issue here in this ticket, but I thought we'd have to call it anywhere we need to PATCH, that's why I put it in solid-logic. Nice to know that it self heals, I did not realize that. I tried so many things I lost track of retrying things.
Once we hear from Noel I can revert my changes and in the profile-pane just call editable check.
bourgeoa commentedon Sep 14, 2026
@SharonStrats If you agree I shall work on solid-logic to implement the missing part of UVDSL related to incomplete life cycle.
SharonStrats commentedon Sep 14, 2026
@bourgeoa thank you! What you mention makes sense and I think making a PR would be great. Before merge let's just see what @NoelDeMartin has to say, because I had a PR adding it to solid-logic (although not in the best way) and he didn't approve. But what you say here, I think it makes a lot of sense.
I'll take care of the changes to revert the solid-logic function, remove the listener in solid-ui that I added, and change profile-pane to only call check Editable not the solid-logic function.
We can create a ticket for the other known places you listed to do the checkeditable and I can do them at some point. Lets discuss how soon we should do it on Wednesday.
NoelDeMartin commentedon Sep 15, 2026
Hey, the only reason I rejected those PRs is that the code was implemented as a side-effect, which should be avoided for tree-shaking and unintended side-effects when importing functions, etc. As long as the code is not implemented like that, I'd probably be ok with it.
timea-solid commentedon Sep 23, 2026
Please link the PRs to this ticket. @bourgeoa
bourgeoa commentedon Sep 23, 2026
Still an open issue uvdsl/solid-oidc-client-browser#36 to remove the temporary cookie patch in solid-logic
timea-solid commentedon Sep 25, 2026
Really really great work!