{"record":{"id":"62ed0786078a5d18","repo":"grafana/grafana","slug":"livenow-is-not-a-boolean","errorCode":null,"errorMessage":"LiveNow is not a boolean","messagePattern":"LiveNow is not a boolean","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"public/app/features/dashboard-scene/serialization/transformSceneToSaveModelSchemaV2.ts","lineNumber":878,"sourceCode":"    throw new Error('Layout is not an object or is null');\n  }\n\n  // Optional properties - only validate if present\n  if ('description' in dash && dash.description !== undefined && typeof dash.description !== 'string') {\n    throw new Error('Description is not a string');\n  }\n  if ('cursorSync' in dash && dash.cursorSync !== undefined) {\n    const validCursorSyncValues = ((): string[] => {\n      const typeValues: DashboardCursorSync[] = ['Off', 'Crosshair', 'Tooltip'];\n      return typeValues;\n    })();\n\n    if (typeof dash.cursorSync !== 'string' || !validCursorSyncValues.includes(dash.cursorSync)) {\n      throw new Error('CursorSync is not a valid value');\n    }\n  }\n  if ('liveNow' in dash && dash.liveNow !== undefined && typeof dash.liveNow !== 'boolean') {\n    throw new Error('LiveNow is not a boolean');\n  }\n  if ('preload' in dash && dash.preload !== undefined && typeof dash.preload !== 'boolean') {\n    throw new Error('Preload is not a boolean');\n  }\n  if ('editable' in dash && dash.editable !== undefined && typeof dash.editable !== 'boolean') {\n    throw new Error('Editable is not a boolean');\n  }\n  if ('links' in dash && dash.links !== undefined && !Array.isArray(dash.links)) {\n    throw new Error('Links is not an array');\n  }\n  if ('tags' in dash && dash.tags !== undefined && !Array.isArray(dash.tags)) {\n    throw new Error('Tags is not an array');\n  }\n  if ('id' in dash && dash.id !== undefined && typeof dash.id !== 'number') {\n    throw new Error('ID is not a number');\n  }\n\n  // Time settings validation","sourceCodeStart":860,"sourceCodeEnd":896,"githubUrl":"https://github.com/grafana/grafana/blob/ae3104e3690e28e72c8f0c97efc12647a70f75c3/public/app/features/dashboard-scene/serialization/transformSceneToSaveModelSchemaV2.ts#L860-L896","documentation":"Thrown by validateDashboardSchemaV2 (transformSceneToSaveModelSchemaV2.ts:878) when dash.liveNow is present but typeof is not 'boolean'. liveNow is an optional boolean on the V2 spec controlling live (auto-refresh-now) dashboards; the guard rejects stringified booleans or numbers. transformSceneToSaveModelSchemaV2 rewraps the throw as a transform error, aborting the save.","triggerScenarios":"validateDashboardSchemaV2 receives a dash object whose liveNow is e.g. 'true' (string), 1, or null; this happens when the object was deserialized from JSON/query params that stringified the flag, or when a custom producer omitted the Boolean() coercion that getLiveNow() normally applies.","commonSituations":"Loading dashboards from URL query strings or REST payloads where booleans arrive as strings; migration code that copies raw fields without coercion; snapshots imported from tools that serialize booleans as 0/1.","solutions":["Coerce the source value with Boolean() (as getLiveNow already does) before building the spec.","Delete the liveNow key when the source value is undefined so the optional-property branch is skipped.","Type the producer against DashboardV2Spec so a non-boolean is caught at compile time."],"exampleFix":"// before\nconst dash = { ...spec, liveNow: payload.liveNow }; // payload.liveNow === 'true'\n// after\nconst dash = { ...spec, liveNow: payload.liveNow == null ? undefined : Boolean(payload.liveNow) };","handlingStrategy":"validation","validationCode":"if ('liveNow' in dash && dash.liveNow !== undefined && typeof dash.liveNow !== 'boolean') {\n  throw new Error(`liveNow must be boolean, got ${typeof dash.liveNow}`);\n}","typeGuard":"function isBool(v: unknown): v is boolean { return typeof v === 'boolean'; }\n// usage: if (dash.liveNow != null && !isBool(dash.liveNow)) { dash.liveNow = Boolean(dash.liveNow); }","tryCatchPattern":"try {\n  validateDashboardSchemaV2(dash);\n} catch (e) {\n  if (String(e).includes('LiveNow')) { dash.liveNow = Boolean((dash as any).liveNow); validateDashboardSchemaV2(dash); }\n  else throw e;\n}","preventionTips":["Always wrap liveNow producers in Boolean() (getLiveNow already does).","Omit the key when undefined rather than passing null/strings.","Run imported payloads through a coerce-booleans pass."],"tags":["validation","dashboard-schema-v2","type-coercion","boolean"],"backgroundTag":null,"analyzedSha":"ae3104e3690e28e72c8f0c97efc12647a70f75c3","analyzedAt":"2026-08-12T12:48:38.752Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}