Looking at how content types are resolved, it seems like they are coupled to the extension of the document when creating it.
In my apps, I create documents without an extension (because I think documents should be serialization agnostic, for example in JSS I don't care if it's stored using JsonLD or Turtle, as long as it returns what I ask with content negotiation). Because of that, when the resolution algorithm tries to detect the content type of a document, it defaults to "application/octet-stream" and falls back to returning the raw document without content negotiation.
If you want to reproduce this, just use Ramen against a JSS instance.
Thanks for the careful debugging and filing the issue. Highlighting the extension-less case with a clear trace is very useful.
We recently published a content-negotiation position document that captures the architectural reasoning. The document is a living one and evolves as the standards progress. Today, any app speaking JSON-LD is fully supported in JSS when --conneg is enabled. Bidirectional Turtle ↔ JSON-LD negotiation works on any URI with a recognised RDF extension, and JSS handles its side when clients implement theirs.
For Ramen today, include a recognised RDF extension in resource URIs (.jsonld or .ttl) and --conneg will handle bidirectional transcoding transparently. The extension-less case with an explicit Accept header is currently the gap. JSS follows standard web content-negotiation patterns and returns application/octet-stream per HTTP spec when format information is missing.
One approach we are considering is enforcing a stricter write-time contract under --conneg, catching missing format information at PUT rather than handling it at GET. This prevents the bug at the source while staying aligned with evolving specs.
We are happy to continue the conversation out of band and appreciate any observations that help sharpen both JSS and the LWS spec.
JSS follows standard web content-negotiation patterns and returns application/octet-stream per HTTP spec when format information is missing.
Well, I guess this is an implementation detail rather than a spec thing. Given that JSS is the one that has written the content of the file, shouldn't the server itself know what's the actual format of the data? Regardless of the format that was used to write it. I don't think relying on url extensions is the right approach.
For example, I think other servers use $.ttl internally to denote the format of the stored file in case it wasn't told explicitly. Maybe this could be the same here? Just that instead of storing turtle, it seems like JSS's preferred format is JsonLD, so you could store files without extensions as $.jsonld (whilst still respecting the extension-less name for urls, etc.).
Activity
melvincarvalho commented on May 16, 2026
Thanks for the careful debugging and filing the issue. Highlighting the extension-less case with a clear trace is very useful.
We recently published a content-negotiation position document that captures the architectural reasoning. The document is a living one and evolves as the standards progress. Today, any app speaking JSON-LD is fully supported in JSS when --conneg is enabled. Bidirectional Turtle ↔ JSON-LD negotiation works on any URI with a recognised RDF extension, and JSS handles its side when clients implement theirs.
For Ramen today, include a recognised RDF extension in resource URIs (.jsonld or .ttl) and --conneg will handle bidirectional transcoding transparently. The extension-less case with an explicit Accept header is currently the gap. JSS follows standard web content-negotiation patterns and returns application/octet-stream per HTTP spec when format information is missing.
One approach we are considering is enforcing a stricter write-time contract under --conneg, catching missing format information at PUT rather than handling it at GET. This prevents the bug at the source while staying aligned with evolving specs.
We are happy to continue the conversation out of band and appreciate any observations that help sharpen both JSS and the LWS spec.
https://jss.live/docs/core-concepts/content-negotiation/
NoelDeMartin commented on May 16, 2026
Well, I guess this is an implementation detail rather than a spec thing. Given that JSS is the one that has written the content of the file, shouldn't the server itself know what's the actual format of the data? Regardless of the format that was used to write it. I don't think relying on url extensions is the right approach.
For example, I think other servers use $.ttl internally to denote the format of the stored file in case it wasn't told explicitly. Maybe this could be the same here? Just that instead of storing turtle, it seems like JSS's preferred format is JsonLD, so you could store files without extensions as $.jsonld (whilst still respecting the extension-less name for urls, etc.).
bourgeoa commented on May 16, 2026
A Solid Resource is made of a Content + content type.
When mapped to a filesystem the file must store both to be able to retrieve both.
The server shall not change the initial Resource contentType that was send via PUT/POST and restore it on GET without content negociation