diff --git a/ivette/src/dome/renderer/data/json.ts b/ivette/src/dome/renderer/data/json.ts
index 63e3ed2354b8bec681e80fce604c60339e548bd0..11f7a039384b5a76bcf6a106b9b096adc4c44825 100644
--- a/ivette/src/dome/renderer/data/json.ts
+++ b/ivette/src/dome/renderer/data/json.ts
@@ -47,13 +47,54 @@ export type jobject = { [key: string]: json };
    Stores a string telling what was expected and a json of what have been
    given */
 
-class JsonError extends Error {
-  expected = '';
-  constructor(expected: string, given: json) {
-    super(`expected ${expected} but given ${given}`);
+export class JsonError extends Error {
+  given: json;
+
+  constructor(given: json) {
+    super("wrong json data type");
     this.name = this.constructor.name;
+    this.given = given;
+  }
+}
+
+class JsonTypeError extends JsonError {
+  expected: string;
+
+  constructor(expected: string, given: json) {
+    super(given);
     this.expected = expected;
   }
+
+  toString(): string {
+    return `expected ${this.expected} but given ${JSON.stringify(this.given)}`;
+  }
+}
+
+class JsonUnionError extends JsonError {
+  #errors: JsonError[];
+
+  constructor(errors: JsonError[], given: json) {
+    super(given);
+    this.#errors = errors;
+  }
+
+  get errors(): JsonTypeError[] {
+    let errorsDeep: JsonTypeError[] = [];
+    this.#errors.forEach(e => {
+      if (e instanceof JsonTypeError) {
+        errorsDeep.push(e);
+      }
+      else if (e instanceof JsonUnionError) {
+        errorsDeep = errorsDeep.concat(e.errors);
+      }
+    });
+    return errorsDeep;
+  }
+
+  toString(): string {
+    return 'none of the union options are valid.\n' +
+      this.errors.map((e) => `  - ${e}`).join('\n');
+  }
 }
 
 /**
@@ -124,10 +165,10 @@ export function identity<A>(v: A): A { return v; }
 export const jNull: Decoder<null> = (js: json) => {
   if (js === null) {
     return null;
-  }
-  else {
-    throw new JsonError("null", js);
-  }
+   }
+   else {
+    throw new JsonTypeError("null", js);
+   }
 };
 
 /** Identity. */
@@ -139,7 +180,7 @@ export const jObj: Decoder<jobject> = (js: json) => {
     return js;
   }
   else {
-    throw new JsonError("object", js);
+    throw new JsonTypeError("object", js);
   }
 };
 
@@ -149,7 +190,7 @@ export const jNumber: Decoder<number> = (js: json) => {
     return js;
   }
   else {
-    throw new JsonError("object", js);
+    throw new JsonTypeError("number", js);
   }
 };
 
@@ -159,7 +200,7 @@ export const jInt: Decoder<number> = (js: json) => {
     return js;
   }
   else {
-    throw new JsonError("integer", js);
+    throw new JsonTypeError("integer", js); 
   }
 };
 
@@ -174,7 +215,7 @@ export const jBoolean: Decoder<boolean> = (js: json) => {
     return js;
   }
   else {
-    throw new JsonError("boolean", js);
+    throw new JsonTypeError("boolean", js); 
   }
 };
 
@@ -190,14 +231,14 @@ export const jFalse: Decoder<boolean> = (js: json) => (
 
 /** Primitive JSON string or throws JsonError. */
 export const jString: Decoder<string> = (js: json) => {
-  if (typeof js === 'string') {
-    return js;
-  }
-  else {
-    throw new JsonError("string", js);
-  }
-};
-
+    if (typeof js === 'string') {
+      return js;
+    }
+    else {
+      throw new JsonTypeError("string", js); 
+    }
+  };
+  
 
 /** JSON constant.
     Capture the tag or throw JsonError.
@@ -210,7 +251,7 @@ export function jTag<A>(tg: A): Decoder<A> {
       return tg;
     }
     else {
-      throw new JsonError(`"${tg}"`, js);
+      throw new JsonTypeError(`"${tg}"`, js); 
     }
   };
 }
@@ -226,7 +267,7 @@ export function jEnum<A>(d: { [tag: string]: A }): Decoder<A> {
     }
     else {
       const tags = Object.keys(d).map((tg) => `"${tg}"`);
-      throw new JsonError(tags.join(' | '), js);
+      throw new JsonTypeError(tags.join(' | '), js);
     }
   };
 }
@@ -245,7 +286,7 @@ export function jTags<A extends string | number>(...values: A[]): Decoder<A> {
     }
     else {
       const tags = values.map((tg) => typeof tg === 'string' ? `"${tg}"` : tg);
-      throw new JsonError(tags.join(' | '), js);
+      throw new JsonTypeError(tags.join(' | '), js);
     }
   };
 }
@@ -293,7 +334,7 @@ export function jMap<A>(fn: Decoder<A>): Decoder<Map<string, A>> {
       return m;
     }
     else {
-      throw new JsonError('object', js);
+      throw new JsonTypeError('object', js);
     }
   };
 }
@@ -324,7 +365,7 @@ export function jArray<A>(fn: Decoder<A>): Decoder<A[]> {
       return js.map(fn);
     }
     else {
-      throw new JsonError('array', js);
+      throw new JsonTypeError('array', js);
     }
   };
 }
@@ -354,7 +395,7 @@ export function jList<A>(fn: Decoder<A>): Decoder<A[]> {
       return buffer;
     }
     else {
-      throw new JsonError('array', js);
+      throw new JsonTypeError('array', js);
     }
   };
 }
@@ -385,7 +426,7 @@ export function jPair<A, B>(
       return [fa(js[0]) as A, fb(js[1]) as B];
     }
     else {
-      throw new JsonError('[A, B]', js);
+      throw new JsonTypeError('[A, B]', js);
     }
   };
 }
@@ -401,7 +442,7 @@ export function jTriple<A, B, C>(
       return [fa(js[0]), fb(js[1]), fc(js[2])];
     }
     else {
-      throw new JsonError('[A, B, C]', js);
+      throw new JsonTypeError('[A, B, C]', js);
     }
   };
 }
@@ -418,7 +459,7 @@ export function jTuple4<A, B, C, D>(
       return [fa(js[0]), fb(js[1]), fc(js[2]), fd(js[3])];
     }
     else {
-      throw new JsonError('[A, B, C, D]', js);
+      throw new JsonTypeError('[A, B, C, D]', js);
     }
   };
 }
@@ -436,7 +477,7 @@ export function jTuple5<A, B, C, D, E>(
       return [fa(js[0]), fb(js[1]), fc(js[2]), fd(js[3]), fe(js[4])];
     }
     else {
-      throw new JsonError('[A, B, C, D, E]', js);
+      throw new JsonTypeError('[A, B, C, D, E]', js);
     }
   };
 }
@@ -463,7 +504,7 @@ export function jObject<A extends object>(decoders: Props<A>): Decoder<A> {
       return buffer as A; // All fields should be present
     }
     else {
-      throw new JsonError('object', js);
+      throw new JsonTypeError('object', js);
     }
   };
 }
@@ -473,14 +514,14 @@ export function jObject<A extends object>(decoders: Props<A>): Decoder<A> {
  */
 export function jUnion<A>(...cases: Decoder<A>[]): Decoder<A> {
   return (js: json) => {
-    const errors = [];
+    const errors: JsonError[] = [];
     for (const fv of cases) {
       try {
         return fv(js);
       }
       catch (err) {
         if (err instanceof JsonError) {
-          errors.push(err.expected);
+          errors.push(err);
           continue;
         }
         else {
@@ -488,7 +529,7 @@ export function jUnion<A>(...cases: Decoder<A>[]): Decoder<A> {
         }
       }
     }
-    throw new JsonError(errors.join(' or '), js);
+    throw new JsonUnionError(errors, js);
   };
 }
 
@@ -548,7 +589,7 @@ export function jKey<K>(kd: K): Decoder<key<K>> {
       return forge(kd, js);
     }
     else {
-      throw new JsonError(`key<${kd}>`, js);
+      throw new JsonTypeError(`key<${kd}>`, js); 
     }
   };
 }
@@ -560,7 +601,7 @@ export function jIndex<K>(kd: K): Decoder<index<K>> {
       return forge(kd, js);
     }
     else {
-      throw new JsonError(`index<${kd}>`, js);
+      throw new JsonTypeError(`index<${kd}>`, js); 
     }
   };
 }
diff --git a/ivette/src/frama-c/server.ts b/ivette/src/frama-c/server.ts
index d4f5c94ba9e6456f2dc163598f58a34b0b62610f..2d404a244c3fa91dfacbc3135df8d727def34985 100644
--- a/ivette/src/frama-c/server.ts
+++ b/ivette/src/frama-c/server.ts
@@ -764,7 +764,13 @@ export function send<In, Out>(
       try {
         resolve(request.output(js));
       } catch (err) {
-        reject(`Invalid ${request.name} response (${err})`);
+        const message = `Invalid ${request.name} response: ${err}`;
+        if (err instanceof Json.JsonError) {
+          reject(`${message}\nThe whole response was:\n${Json.stringify(js)}`);
+        }
+        else {
+          reject(message);
+        }
       }
     };
     pending.set(rid, { resolve: unwrap, reject });
diff --git a/src/plugins/server/kernel_properties.ml b/src/plugins/server/kernel_properties.ml
index f07736aa5202b5d706ef413f81c33b1493eef696..9dbdcb8872383edef7505de55b4033f3a396addb 100644
--- a/src/plugins/server/kernel_properties.ml
+++ b/src/plugins/server/kernel_properties.ml
@@ -321,15 +321,20 @@ let is_relevant ip =
     not (Ast_info.is_frama_c_builtin (Kernel_function.get_name kf)
          || Cil_builtins.is_unused_builtin (Kernel_function.get_vi kf))
 
-let iter f = Property_status.iter (fun ip -> if is_relevant ip then f ip)
+let iter f =
+  Property_status.iter (fun ip -> if is_relevant ip then f ip)
 
-let add_update_hook f =
-  Property_status.register_property_add_hook
-    (fun ip -> if is_relevant ip then f ip);
+(* Must reload the entire table when status changed: property dependencies
+   are not taken into account when status are updated. *)
+let add_reload_hook (f : unit -> unit) : unit =
   Property_status.register_status_update_hook
-    (fun _emitter ip _status -> if is_relevant ip then f ip)
+    (fun _emitter _ip _status -> f())
+
+let add_update_hook (f : Property.t -> unit) : unit =
+  Property_status.register_property_add_hook
+    (fun ip -> if is_relevant ip then f ip)
 
-let add_remove_hook f =
+let add_remove_hook (f : Property.t -> unit) : unit =
   Property_status.register_property_remove_hook
     (fun ip -> if is_relevant ip then f ip)
 
@@ -341,8 +346,9 @@ let array =
     ~key:(fun ip -> Kernel_ast.Marker.tag (PIP ip))
     ~keyType:Kernel_ast.Marker.jtype
     ~iter
-    ~add_update_hook
+    ~add_reload_hook
     ~add_remove_hook
+    ~add_update_hook
     model
 
 let reload () = States.reload array