{"record":{"id":"304b6718a43b767f","repo":"windmill-labs/windmill","slug":"not-a-fileset-resource-path-changepath","errorCode":null,"errorMessage":"Not a fileset resource path: ${changePath}","messagePattern":"Not a fileset resource path: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/src/commands/sync/sync.ts","lineNumber":1039,"sourceCode":"      filesetMap[k] = false;\n    } else {\n      if (v.format_extension) {\n        formatExtMap[k] = v.format_extension;\n      }\n      filesetMap[k] = v.is_fileset ?? false;\n    }\n  }\n  return { formatExtMap, filesetMap };\n}\n\nexport async function findFilesetResourceFile(\n  changePath: string,\n  wsName?: string | null,\n): Promise<string> {\n  // Extract the base path before .fileset/\n  const filesetIdx = changePath.indexOf(\".fileset\" + SEP);\n  if (filesetIdx === -1) {\n    throw new Error(`Not a fileset resource path: ${changePath}`);\n  }\n  const basePath = changePath.substring(0, filesetIdx);\n  const candidates = [basePath + \".resource.json\", basePath + \".resource.yaml\"];\n  // A workspace-specific resource keeps its children at the server-canonical\n  // `<base>.fileset/` while its metadata file carries the workspace suffix.\n  // The suffixed file is this workspace's authoritative metadata, so it must\n  // win over a base file that coexists with it.\n  if (wsName) {\n    candidates.unshift(\n      toWorkspaceSpecificPath(basePath + \".resource.json\", wsName),\n      toWorkspaceSpecificPath(basePath + \".resource.yaml\", wsName),\n    );\n  }\n\n  for (const candidate of candidates) {\n    try {\n      const s = await stat(candidate);\n      if (s.isFile()) return candidate;","sourceCodeStart":1021,"sourceCodeEnd":1057,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/cli/src/commands/sync/sync.ts#L1021-L1057","documentation":"findFilesetResourceFile() maps a change path inside a fileset resource (a resource whose files live under `<base>.fileset/`) back to its parent metadata file (`<base>.resource.json` or `.resource.yaml`). The CLI throws this error when the given path does not contain a `.fileset/` segment, so it cannot be a fileset child and no parent resource can be derived from it. It is an internal invariant guard: callers are expected to pass only paths discovered under a `.fileset/` directory.","triggerScenarios":"Calling findFilesetResourceFile (directly or via pushFilesetParentResource during `wmill sync push`) with a change path that lacks `.fileset` + separator — e.g. a plain `foo.resource.json` path, a misbuilt path where the separator SEP differs from the one used on disk, or a hand-edited watcher/sync input.","commonSituations":"Running sync on a checkout where a resource was renamed so its `.fileset/` folder and the metadata file no longer line up; cross-platform checkouts (Windows vs POSIX separators) altering path formats; custom tooling feeding non-fileset paths into the fileset push flow.","solutions":["Check the path actually contains a `.fileset/` segment; if it is a plain resource metadata file, route it through the normal resource push instead of the fileset flow","Verify SEP matches your OS path separator and that the path was not normalized to use a different separator","Re-pull the resource (`wmill sync pull`) so the `.fileset/` folder and metadata file are regenerated consistently","If calling findFilesetResourceFile yourself, pre-check `path.includes('.fileset' + SEP)` and handle non-fileset paths separately"],"exampleFix":"// before\nconst meta = await findFilesetResourceFile(changePath, ws); // throws on plain paths\n// after\nif (!changePath.includes('.fileset' + SEP)) {\n  await pushResourceFile(changePath); // normal resource path\n} else {\n  const meta = await findFilesetResourceFile(changePath, ws);\n}","handlingStrategy":"validation","validationCode":"import * as path from 'path';\nconst SEP = path.sep;\nfunction isFilesetResourcePath(changePath: string): boolean {\n  return changePath.includes('.fileset' + SEP);\n}\n// call findFilesetResourceFile only if isFilesetResourcePath(p)\n","typeGuard":"function isFilesetPath(p: string): p is `${string}.fileset/${string}` {\n  return p.includes('.fileset/');\n}","tryCatchPattern":"try {\n  const meta = await findFilesetResourceFile(changePath, ws);\n} catch (e) {\n  if (String(e).message.startsWith('Not a fileset resource path')) {\n    // fall back to normal resource handling\n  } else throw e;\n}","preventionTips":["Pre-check the path contains '.fileset' + SEP before invoking the fileset flow","Route plain resource metadata files through the normal resource push path","Keep path separators consistent (use path.join, don't mix / and \\\\ manually)"],"tags":["cli","sync","fileset","path-parsing"],"backgroundTag":"invalid-resource-path","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}