JuliusBrussee/caveman · error · MiddlewareError
unknown_capability
unknown_capability
Error message
unknown_capability
What it means
MiddlewareError with code 'unknown_capability' is thrown by validateCapabilities when a transform entry in a Capabilities object fails leaf validation. The library validates every declared transform before an adapter is allowed to apply any of them, so a single malformed transform invalidates the whole capability set. Checks include token-shaped transform_id (unique), token-shaped implementation_version, an array eligible_segment_kinds, recovery of 'exact_ccr' or 'none', and deterministic === true.
Solutions
- Fix the offending transform entry: make transform_id and implementation_version valid tokens and ensure each transform_id is unique in the array
- Set recovery to exactly 'exact_ccr' or 'none'
- Set deterministic to the boolean true (not 1, not a string)
- Ensure eligible_segment_kinds is a non-null array of segment kinds
- Log/inspect the capabilities object before validation to find which transform fails
Example fix
// before
{ transform_id: 'compress json', recovery: 'exact', deterministic: 1 }
// after
{ transform_id: 'compress-json', implementation_version: '1.0.0', eligible_segment_kinds: ['json'], recovery: 'exact_ccr', deterministic: true } Defensive patterns
Strategy: validation
Validate before calling
function validTransform(t) {
return t && isToken(t.transform_id) && isToken(t.implementation_version) &&
Array.isArray(t.eligible_segment_kinds) &&
['exact_ccr','none'].includes(t.recovery) && t.deterministic === true;
}
const seen = new Set();
if (!c.transforms.every(t => validTransform(t) && !seen.has(t.transform_id) && seen.add(t.transform_id)))
throw new Error('capability transform invalid before calling validateCapabilities'); Type guard
const isCapabilities = (c) => !!c && c.schema_version === 1 && Array.isArray(c.transforms) &&
c.transforms.every(t => typeof t?.transform_id === 'string' && typeof t?.deterministic === 'boolean' &&
(t.recovery === 'exact_ccr' || t.recovery === 'none')); Try / catch
try { await validateCapabilities(value); } catch (e) {
if (e.code === 'unknown_capability') {
const bad = value.transforms.findIndex(t => !isCapabilities({ transforms: [t] }));
console.error(`invalid transform at index ${bad}:`, value.transforms[bad]);
} else throw e;
} Prevention
- Generate capability manifests from a schema-validated source rather than hand-writing them
- Keep transform_id values unique and token-shaped (no spaces/special chars)
- Always use boolean true for deterministic, never 1
- Add a unit test that runs every shipped capability set through validateCapabilities
When it happens
Trigger: Calling validateCapabilities with a Capabilities object whose transforms array contains: a transform_id that is not a valid token, a duplicate transform_id, an implementation_version that is not a token, eligible_segment_kinds missing or not an array, a recovery value other than 'exact_ccr'/'none', or deterministic not strictly true.
Common situations: Hand-written capability manifests with typos in recovery ('exact', 'ccr'), deterministic omitted or set to 1 instead of true, the same transform listed twice after copy-paste, kebab/underscored transform ids failing isToken, or an upgrade that renamed recovery enum values.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- : capabilities must be an object
- canonical span
- cave_agent_definition_invalid
- cave_context_ir_invalid
- cave_output_schema_mismatch
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/5bb64bd81331da3b.
Report an issue: GitHub.
Appendix: source
Thrown at packages/sdk/typescript/src/middleware/validate.ts:27
export const isToken = (s: unknown): s is string => typeof s === 'string' && /^[a-zA-Z0-9._:/-]{1,256}$/.test(s);
const integer = (n: unknown): n is number => Number.isSafeInteger(n) && (n as number) >= 0;
export function scopeKey(scope: Scope): string {
if (![scope.namespace, scope.session_id, scope.branch_id, scope.cache_epoch].every(isToken)) throw new MiddlewareError('invalid_scope');
return JSON.stringify([scope.namespace, scope.session_id, scope.branch_id, scope.cache_epoch]);
}
export class MiddlewareError extends Error {
constructor(readonly code: string) { super(`Caveman middleware: ${code}`); this.name = 'MiddlewareError'; }
}
export function validateCapabilities(value: unknown): Capabilities {
const c = value as Capabilities;
if (!c || c.schema_version !== 1 || !isToken(c.policy_revision) || typeof c.runtime_build !== 'string' ||
!['record', 'compress'].includes(c.mode) || !Array.isArray(c.transforms) || c.transforms.length > 128 ||
!c.limits || !Object.values(c.limits).every(n => integer(n) && n > 0) ||
!integer(c.retention_seconds) || typeof c.recovery !== 'boolean' || typeof c.persistent !== 'boolean') throw new MiddlewareError('unsupported_version');
const ids = new Set<string>();
for (const t of c.transforms) {
if (!isToken(t.transform_id) || ids.has(t.transform_id) || !isToken(t.implementation_version) || !Array.isArray(t.eligible_segment_kinds) ||
!['exact_ccr', 'none'].includes(t.recovery) || t.deterministic !== true) throw new MiddlewareError('unknown_capability');
ids.add(t.transform_id);
}
return c;
}
/** Validate every leaf before an adapter is allowed to apply any of them. */
export async function validatePlan(value: unknown, request: OptimizeRequest, inputDigest: string, caps: Capabilities): Promise<Plan> {
const p = value as Plan;
const invalid = () => { throw new MiddlewareError('invalid_plan'); };
if (!p || p.schema_version !== 1 || p.request_id !== request.request_id || p.input_digest !== inputDigest ||
p.policy_revision !== request.policy.revision || !isHash(p.replacement_set_id) || !['optimized','bypassed','record'].includes(p.status) ||
!isToken(p.reason) || !Array.isArray(p.replacements) || !Array.isArray(p.skipped) || !p.measurement || !p.stability || !p.recovery) invalid();
const m = p.measurement;
if (m.basis !== 'inferred' || m.scope !== 'segment' || m.verified_saved_usd !== 0 || typeof m.tokenizer !== 'string' ||
![m.tokens_before,m.tokens_after,m.unique_tokens_reduced,m.recovery_overhead_tokens].every(integer) || m.tokens_after > m.tokens_before ||
p.stability.provider_bytes !== 'unobserved' || p.stability.provider_cache_hits !== 'unobserved' || !['persistent_choices','unavailable'].includes(p.stability.native) ||
typeof p.recovery.available !== 'boolean' || typeof p.recovery.persistent !== 'boolean' || !integer(p.recovery.expires_at)) invalid();
const seen = new Set<string>();View on GitHub (pinned to 3ee70a1026)