{"record":{"id":"2e02542e6db93b45","repo":"grafana/grafana","slug":"variables-is-not-an-array","errorCode":null,"errorMessage":"Variables is not an array","messagePattern":"Variables is not an array","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"public/app/features/dashboard-scene/serialization/transformSceneToSaveModelSchemaV2.ts","lineNumber":851,"sourceCode":"\n  return spec;\n}\n\n// Function to know if the dashboard transformed is a valid DashboardV2Spec\nexport function validateDashboardSchemaV2(dash: unknown): dash is DashboardV2Spec {\n  if (typeof dash !== 'object' || dash === null || Array.isArray(dash)) {\n    throw new Error('Dashboard is not an object or is null');\n  }\n\n  // Required properties\n  if (!('title' in dash) || typeof dash.title !== 'string') {\n    throw new Error('Title is not a string');\n  }\n  if (!('timeSettings' in dash) || typeof dash.timeSettings !== 'object' || dash.timeSettings === null) {\n    throw new Error('TimeSettings is not an object or is null');\n  }\n  if (!('variables' in dash) || !Array.isArray(dash.variables)) {\n    throw new Error('Variables is not an array');\n  }\n  if (!('elements' in dash) || typeof dash.elements !== 'object' || dash.elements === null) {\n    throw new Error('Elements is not an object or is null');\n  }\n  if (!('annotations' in dash) || !Array.isArray(dash.annotations)) {\n    throw new Error('Annotations is not an array');\n  }\n  if (!('layout' in dash) || typeof dash.layout !== 'object' || dash.layout === null) {\n    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'];","sourceCodeStart":833,"sourceCodeEnd":869,"githubUrl":"https://github.com/grafana/grafana/blob/ae3104e3690e28e72c8f0c97efc12647a70f75c3/public/app/features/dashboard-scene/serialization/transformSceneToSaveModelSchemaV2.ts#L833-L869","documentation":"Required-field check: variables must be an array. V2 stores variables as a list (each entry is a typed variable spec), unlike V1's object map. Thrown when the transformed dashboard has no variables key or a non-array value.","triggerScenarios":"getVariables(sceneDash, dsReferencesMapping) returned undefined or an object instead of an array. Happens when the scene has no variables layer or the variables serializer changed shape.","commonSituations":"Dashboard without any variables (the transformer should still emit []); migration code that returned the V1 object map; refactor of getVariables that dropped the array cast; template variable plugin returning a non-array.","solutions":["Ensure getVariables always returns an array (default to [] when there are no variables).","If migrating from V1, convert the variables object map to the V2 array form before transform.","Add a unit test for the no-variables case.","Type the return of getVariables as DashboardV2Variable[] so the compiler catches regressions."],"exampleFix":"// before\nif (!('variables' in dash) || !Array.isArray(dash.variables)) {\n  throw new Error('Variables is not an array');\n}\n\n// after — guarantee array in the producer\nvariables: getVariables(sceneDash, dsReferencesMapping) ?? [],","handlingStrategy":"type-guard","validationCode":"const vars = getVariables(sceneDash, dsRefs);\nif (!Array.isArray(vars)) throw new Error('getVariables must return an array');","typeGuard":"function isVariablesArray(dash: unknown): dash is { variables: unknown[] } {\n  return typeof dash === 'object' && dash !== null && 'variables' in dash && Array.isArray((dash as any).variables);\n}","tryCatchPattern":"try { await transformSceneToSaveModelSchemaV2(scene); }\ncatch (e) {\n  if (e.message === 'Variables is not an array') reportBug('getVariables returned non-array');\n  else throw e;\n}","preventionTips":["Type getVariables' return as DashboardV2Variable[].","Default to [] when there are no variables.","Unit-test the no-variables transform path."],"tags":["validation","v2","variables","required-field"],"backgroundTag":null,"analyzedSha":"ae3104e3690e28e72c8f0c97efc12647a70f75c3","analyzedAt":"2026-08-12T12:48:38.752Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}