{"record":{"id":"8199c9165de0f7cb","repo":"windmill-labs/windmill","slug":"invalid-file-extension","errorCode":null,"errorMessage":"Invalid file extension","messagePattern":"Invalid file extension","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"frontend/src/routes/(root)/(logged)/resources/+page.svelte","lineNumber":331,"sourceCode":"\t\t)\n\t\tloading.types = false\n\t}\n\n\tasync function deleteResource(path: string, account?: number): Promise<void> {\n\t\tif (account) {\n\t\t\tOauthService.disconnectAccount({ workspace: $workspaceStore!, id: account })\n\t\t}\n\t\tawait ResourceService.deleteResource({ workspace: $workspaceStore!, path })\n\t\treload()\n\t}\n\n\tasync function addResourceType(): Promise<void> {\n\t\tif (!newResourceType.isFileset) {\n\t\t\tif (newResourceType.formatExtension === '') {\n\t\t\t\tthrow new Error('Invalid empty file extension (make sure it is selected)')\n\t\t\t}\n\t\t\tif (!validateFileExtension(newResourceType.formatExtension ?? 'txt')) {\n\t\t\t\tthrow new Error('Invalid file extension')\n\t\t\t}\n\t\t}\n\t\tawait ResourceService.createResourceType({\n\t\t\tworkspace: $workspaceStore!,\n\t\t\trequestBody: {\n\t\t\t\tname: (disableCustomPrefix ? '' : 'c_') + newResourceType.name,\n\t\t\t\tschema: newResourceType.schema,\n\t\t\t\tdescription: newResourceType.description,\n\t\t\t\tformat_extension: newResourceType.formatExtension,\n\t\t\t\tis_fileset: newResourceType.isFileset\n\t\t\t}\n\t\t})\n\t\tresourceTypeDrawer?.closeDrawer?.()\n\t\tsendUserToast('Resource type created')\n\t\tloadResourceTypes()\n\t\t$resourceTypesStore = undefined\n\t}\n","sourceCodeStart":313,"sourceCodeEnd":349,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/frontend/src/routes/(root)/(logged)/resources/+page.svelte#L313-L349","documentation":"addResourceType on the resources page rejects extensions failing validateFileExtension with 'Invalid file extension'. This guards that the extension is syntactically valid (e.g. alphanumeric, no slashes/spaces) before creating the resource type via the API.","triggerScenarios":"Submitting a non-fileset resource type whose formatExtension is non-empty but malformed — contains illegal characters, leading dot, path separators, or whitespace.","commonSituations":"Typing '.json' (with dot) or 'my file.csv' into the extension field; pasting a filename instead of just the extension; unicode or special characters pasted from external docs.","solutions":["Enter only the bare extension (e.g. 'csv', not '.csv' or 'data.csv')","Remove invalid characters (spaces, dots, slashes) from the extension field","If the type really has variable extensions, mark it as a fileset instead"],"exampleFix":"// before\nformatExtension: '.csv'\n// after\nformatExtension: 'csv'","handlingStrategy":"validation","validationCode":"const ext = (newResourceType.formatExtension ?? '').replace(/^\\./, '')\nif (!newResourceType.isFileset && !/^[A-Za-z0-9]+$/.test(ext)) {\n  sendUserToast('Extension must be bare alphanumeric, e.g. csv', true)\n  return\n}","typeGuard":"function isValidExtension(v: unknown): v is string {\n  return typeof v === 'string' && /^[A-Za-z0-9]+$/.test(v)\n}","tryCatchPattern":"try {\n  await addResourceType()\n} catch (e) {\n  if (e.message === 'Invalid file extension') {\n    sendUserToast('Use a bare extension like \"csv\" — no dot, spaces or slashes', true)\n  } else throw e\n}","preventionTips":["Sanitize user input: strip a leading dot and whitespace before validating","Validate with the same regex the page uses (validateFileExtension) before submit","Accept pasted filenames by splitting on '.' and taking the last segment","Mark it as a fileset when no single fixed extension applies"],"tags":["validation","frontend","forms"],"backgroundTag":"invalid-file-extension","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"}