{"record":{"id":"60175d62d65869b9","repo":"hasura/graphql-engine","slug":"files-is-invalid-w","errorCode":null,"errorMessage":"`files` is invalid: %w","messagePattern":"`files` is invalid: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/plugins/util.go","lineNumber":101,"sourceCode":"\n\tif !isValidSHA256(p.Sha256) {\n\t\treturn errors.E(\n\t\t\top,\n\t\t\tfmt.Errorf(\n\t\t\t\t\"`sha256` value %s is not valid, must match pattern %s\",\n\t\t\t\tp.Sha256,\n\t\t\t\tsha256Pattern,\n\t\t\t),\n\t\t)\n\t}\n\n\tif p.Bin == \"\" {\n\t\treturn errors.E(op, \"`bin` has to be set\")\n\t}\n\n\terr := validateFiles(p.Files)\n\tif err != nil {\n\t\treturn errors.E(op, fmt.Errorf(\"`files` is invalid: %w\", err))\n\t}\n\n\treturn nil\n}\n\nfunc validateFiles(fops []FileOperation) error {\n\tvar op errors.Op = \"plugins.validateFiles\"\n\n\tif fops == nil {\n\t\treturn nil\n\t}\n\n\tif len(fops) == 0 {\n\t\treturn errors.E(op, \"`files` has to be unspecified or non-empty\")\n\t}\n\n\tfor _, fop := range fops {\n\t\tif fop.From == \"\" {","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/hasura/graphql-engine/blob/724551b9ae87845594ef0408cff0e50eb6c90dc5/cli/plugins/util.go#L83-L119","documentation":"validatePlatform delegates file-operation checking to validateFiles; if any entry of the files[] array in the platform manifest is malformed (invalid from/to paths or unsupported operation), the failure is wrapped as \"`files` is invalid\". This runs during ValidatePlugin, before any download happens.","triggerScenarios":"A files[] entry with an empty from/to path, an operation string not recognized by validateFiles, or path syntax that fails its checks — triggered by ReadPluginFromFile → ValidatePlugin → validatePlatform.","commonSituations":"Typos in the operation field (\"move\" vs \"rename\"), absolute paths where relative ones are required, or copy-pasted file entries pointing at files that don't exist in the new archive layout.","solutions":["Inspect the wrapped error after the colon — it identifies the exact file-entry problem.","Fix each files[] entry: valid operation, non-empty relative from/to paths.","Re-run ReadPluginFromFile to confirm the manifest validates."],"exampleFix":"// before\n\"files\": [{ \"from\": \"/etc/conf\", \"to\": \"conf\", \"op\": \"move\" }]\n\n// after\n\"files\": [{ \"from\": \"conf\", \"to\": \"conf\", \"op\": \"copy\" }]","handlingStrategy":"validation","validationCode":"for _, f := range pl.Files {\n\tif f.From == \"\" || f.To == \"\" || !knownOps[f.Op] {\n\t\treturn fmt.Errorf(\"bad file entry %+v\", f)\n\t}\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use only documented file operations and relative paths.","Cross-check from paths against the actual archive contents when cutting a release.","Validate the full manifest with ValidatePlugin in CI."],"tags":["plugins","validation","manifest","files"],"backgroundTag":"manifest-field-mismatch","analyzedSha":"724551b9ae87845594ef0408cff0e50eb6c90dc5","analyzedAt":"2026-08-28T07:32:55.105Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}