JuliusBrussee/caveman · critical · Error
cave_eve_runtime_identity_missing
cave_eve_runtime_identity_missing
Error message
cave_eve_runtime_identity_missing
What it means
Returned by ValidateTenantSchema when tenantSchemaViolations finds at least one breach of the structural isolation invariants: a tenant table without FORCE RLS, a missing or wrong-organization_id RLS policy expression (must equal current_setting('app.current_organization_id', ...) with optional casts), a nullable organization_id where it must not be, or a tenant-to-tenant foreign key that does not share the organization scope (plus project scope when both sides have it). Violations are joined with '; ' into one message. This is a security invariant failure: the schema as deployed permits cross-tenant access.
Source
Thrown at packages/agent/src/adapters.ts:480
totalTokens: strictInteger(value.totalTokens, error),
};
if (usage.totalTokens !== usage.inputTokens + usage.outputTokens +
usage.cacheReadTokens + usage.cacheWriteTokens ||
usage.reasoningTokens > usage.outputTokens) {
throw new Error(error);
}
return usage;
}
function eveRuntimeIdentity(events: unknown[]): {
provider: string;
model: string;
upstreamVersion: string;
} {
const starts = events.filter((event) =>
isRecord(event) && event.type === "session.started" && isRecord(event.data) &&
isRecord(event.data.runtime));
if (starts.length !== 1) throw new Error("cave_eve_runtime_identity_missing");
const runtime = (starts[0] as { data: { runtime: Record<string, unknown> } }).data.runtime;
if (typeof runtime.modelId !== "string" || runtime.modelId.length === 0 ||
runtime.modelId.startsWith("dynamic:")) {
throw new Error("cave_eve_runtime_identity_missing");
}
const separator = runtime.modelId.indexOf("/");
if (separator < 1 || separator === runtime.modelId.length - 1 ||
typeof runtime.eveVersion !== "string" || runtime.eveVersion.length === 0) {
throw new Error("cave_eve_runtime_identity_missing");
}
return {
provider: runtime.modelId.slice(0, separator),
model: runtime.modelId.slice(separator + 1),
upstreamVersion: runtime.eveVersion,
};
}
function expectedProviderModel(plan: CavePlan): { provider: string; model: string } {View on GitHub (pinned to 27d5a3981a)
Solutions
- Run ValidateTenantSchema (or the underlying catalog queries) in a dev database and match each violation string to the specific table/policy it names
- For every flagged table: ENABLE and FORCE row level security, create/repair a policy whose USING/WITH CHECK expression equals organization_id = current_setting('app.current_organization_id', true) (allowed casts per the regexp), and make organization_id NOT NULL if required
- Repair flagged foreign keys so they reference (organization_id, id) of the peer tenant table (and include project_id when both tables carry it)
- Add the same checks to CI/migration tests so a non-compliant migration fails before deploy
Example fix
-- before: tenant table without forced RLS
CREATE TABLE invoices (
id bigint PRIMARY KEY,
organization_id bigint NOT NULL REFERENCES organizations(id),
...
); -- validation fails: rls not enabled/forced, policy missing
-- after
ALTER TABLE invoices ENABLE ROW LEVEL SECURITY;
ALTER TABLE invoices FORCE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON invoices
USING (organization_id = current_setting('app.current_organization_id', true))
WITH CHECK (organization_id = current_setting('app.current_organization_id', true)); Defensive patterns
Strategy: validation
Validate before calling
// Standalone check developers can run in a dev DB or migration test:
func assertTenantRLS(ctx context.Context, conn pgx Querier, table string) error {
var rls, force, hasPolicy bool
var notNullOK bool
err := conn.QueryRow(ctx, `
SELECT c.relrowsecurity, c.relforcerowsecurity,
EXISTS (SELECT 1 FROM pg_policy p WHERE p.polrelid = c.oid),
EXISTS (SELECT 1 FROM pg_attribute a
WHERE a.attrelid = c.oid AND a.attname = 'organization_id' AND a.attnotnull)
FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE n.nspname = 'public' AND c.relname = $1`, table).Scan(&rls, &force, &hasPolicy, ¬NullOK)
if err != nil { return err }
if !rls || !force || !hasPolicy || !notNullOK {
return fmt.Errorf("table %s violates tenant isolation (rls=%t force=%t policy=%t org_not_null=%t)", table, rls, force, hasPolicy, notNullOK)
}
return nil
} Type guard
func isIsolationViolationErr(err error) bool {
return err != nil && strings.HasPrefix(err.Error(), "postgres: tenant schema isolation incomplete")
} Try / catch
if err := postgresconfig.ValidateTenantSchema(ctx, pool); err != nil {
if isIsolationViolationErr(err) {
// SECURITY: do not catch-and-continue serving traffic.
// Parse the '; '-joined violations, fix each table's RLS/policy/FK in migrations, redeploy.
log.Fatalf("tenant isolation violated: %v", err)
}
return err // other errors: infra, see indices 15-17,19
} Prevention
- Add ValidateTenantSchema (or per-table assertions) to migration tests in CI so a non-compliant migration never merges
- Standardize a tenant-table migration template: organization_id BIGINT NOT NULL, ENABLE+FORCE ROW LEVEL SECURITY, policy using current_setting('app.current_organization_id', true)
- Require tenant-to-tenant FKs to include organization_id (and project_id when both sides have it)
- Never disable RLS 'temporarily' in production; treat it as a security regression
- On violation, do not serve tenant traffic: fail the startup gate closed
When it happens
Trigger: Adding a tenant table (one with organization_id) in a migration without ALTER TABLE ... ENABLE ROW LEVEL SECURITY / FORCE ROW LEVEL SECURITY and a matching policy; changing a policy expression so it no longer references app.current_organization_id; adding an FK from one tenant table to another keyed only on id; making organization_id nullable on a table the checker requires to be scoped.
Common situations: A new feature table slipped into a migration without the RLS boilerplate; a DBA 'optimizing' or disabling RLS on a slow table; refactoring the tenant-context GUC name without updating every policy; backfills that drop NOT NULL on organization_id temporarily and shipping before restoring.
Related errors
- cave_mastra_terminal_failure
- cave_harness_incomplete_evidence
- cave_vercel_usage_missing
- cave_mastra_usage_missing
- cave_eve_usage_missing
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/05c95d0efdb95bf8.
Report an issue: GitHub.