This is a usage/idiom question about encoding against type-erased schemas.
When you only have a type-erased Schema.Top — e.g. from RPC dynamic dispatch, heterogeneous registries, or plugin systems where the concrete schema type is lost — encoding a value against it as JSON surfaces unknown in the requirements (R) channel:
declare const erased: Schema.Top
const eff = Schema.encodeUnknownEffect(Schema.toCodecJson(erased))(value)
// eff: Effect<Json, SchemaError, unknown> // <- unknown in R
Schema.Top types DecodingServices/EncodingServices as unknown, and toCodecJson + encodeUnknownEffect forward them into R. @effect/language-service flags it as anyUnknownInErrorContext (TS377030, "unknown in the requirements channel"). But such schemas are plain data — they need no codec services (the repro verifies this at runtime).
The only clean fix we found is an unsafe cast asserting the (true) never service channels:
Schema.toCodecJson(erased as Schema.Codec<unknown, unknown, never, never>)
// -> Effect<Json, SchemaError, never>
We confirmed encodeUnknownExit / encodeUnknownResult (which return Exit/Result with no R channel) don't avoid the cast — their ConstraintEncoder<unknown> bound requires EncodingServices extends never, which Schema.Top doesn't satisfy.
Question: is casting the service channels the idiomatic way to encode/decode against a Schema.Top known to need no services, or is there a cleaner, more Effect-native API for this (a service-erasing combinator, an encode variant that ignores services, a better way to type-erase RPC schemas, etc.)?
Reproduction
https://github.com/schickling-repros/2026-07-effect-erased-schema-services
bun install
bun run repro # tsc type-assertions (R=unknown vs R=never) + a runtime check
Versions
- effect:
4.0.0-beta.98
@effect/language-service: anyUnknownInErrorContext (TS377030)
Context: this arises encoding RPC exit/payload schemas after dynamic dispatch erases them to Schema.Top — a follow-on to #6064 (which exposed successSchema but not the service-typing question).
Posted on behalf of @schickling
| field |
value |
agent_name |
🌲 cl1-pine |
agent_session_id |
b9f1f4a5-dd10-40f6-b25c-945e71e2007a |
agent_tool |
Claude Code |
agent_tool_version |
2.1.206 |
agent_runtime |
Claude Code 2.1.206 |
agent_model |
claude-opus-4-8 |
runtime_profile |
/nix/store/1n76sy6i9y3ki3k4w04jksqvygw67sj0-coding-agent-runtime-profile/share/coding-agents/profile.json |
skills_manifest |
/nix/store/jn6r0r7r59x3a525jch4pwzwykszqp60-agent-skills-corpus/share/agent-skills/manifest.json |
worktree |
livestore/schickling/2026-07-17-refactor |
machine |
dev3 |
tooling_profile |
dotfiles@4eac376 |
This is a usage/idiom question about encoding against type-erased schemas.
When you only have a type-erased
Schema.Top— e.g. from RPC dynamic dispatch, heterogeneous registries, or plugin systems where the concrete schema type is lost — encoding a value against it as JSON surfacesunknownin the requirements (R) channel:Schema.ToptypesDecodingServices/EncodingServicesasunknown, andtoCodecJson+encodeUnknownEffectforward them into R.@effect/language-serviceflags it asanyUnknownInErrorContext(TS377030, "unknown in the requirements channel"). But such schemas are plain data — they need no codec services (the repro verifies this at runtime).The only clean fix we found is an unsafe cast asserting the (true)
neverservice channels:We confirmed
encodeUnknownExit/encodeUnknownResult(which returnExit/Resultwith no R channel) don't avoid the cast — theirConstraintEncoder<unknown>bound requiresEncodingServices extends never, whichSchema.Topdoesn't satisfy.Question: is casting the service channels the idiomatic way to encode/decode against a
Schema.Topknown to need no services, or is there a cleaner, more Effect-native API for this (a service-erasing combinator, an encode variant that ignores services, a better way to type-erase RPC schemas, etc.)?Reproduction
https://github.com/schickling-repros/2026-07-effect-erased-schema-services
bun install bun run repro # tsc type-assertions (R=unknown vs R=never) + a runtime checkVersions
4.0.0-beta.98@effect/language-service:anyUnknownInErrorContext(TS377030)Context: this arises encoding RPC exit/payload schemas after dynamic dispatch erases them to
Schema.Top— a follow-on to #6064 (which exposedsuccessSchemabut not the service-typing question).Posted on behalf of @schickling
agent_nameagent_session_idagent_toolagent_tool_versionagent_runtimeagent_modelruntime_profileskills_manifestworktreemachinetooling_profile