{"record":{"id":"88296db7a8d25c60","repo":"theonedev/onedev","slug":"attribute-s-should-start-and-end-with-alphanume","errorCode":null,"errorMessage":"Attribute '%s' should start and end with alphanumeric or underscore. Only alphanumeric, underscore, dash, space and dot are allowed in the middle.","messagePattern":"Attribute '(.+?)' should start and end with alphanumeric or underscore\\. Only alphanumeric, underscore, dash, space and dot are allowed in the middle\\.","errorType":"validation","errorClass":"ExplicitException","httpStatus":null,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/service/impl/DefaultAgentService.java","lineNumber":172,"sourceCode":"\t\t}\n\t}\n\t\n\t@Override\n\tpublic String getAgentVersion() {\n\t\treturn agentVersion;\n\t}\n\n\t@Override\n\tpublic Collection<String> getAgentLibs() {\n\t\treturn agentLibs;\n\t}\n\n\t@Transactional\n\t@Override\n\tpublic Long agentConnected(AgentData data, Session session) {\n\t\tfor (String attributeName: data.getAttributes().keySet()) {\n\t\t\tif (!AttributeNameValidator.PATTERN.matcher(attributeName).matches()) {\n\t\t\t\tthrow new ExplicitException(\"Attribute '\" + attributeName + \"' should start and end with \"\n\t\t\t\t\t\t+ \"alphanumeric or underscore. Only alphanumeric, underscore, dash, space and \"\n\t\t\t\t\t\t+ \"dot are allowed in the middle.\");\n\t\t\t} else if (Agent.ALL_FIELDS.contains(attributeName)) { \n\t\t\t\tthrow new ExplicitException(\"Attribute '\" + attributeName + \"' is reserved\");\n\t\t\t}\n\t\t}\n\t\t\n\t\tAgentToken token = Preconditions.checkNotNull(tokenService.find(data.getToken()));\n\t\tAgent agent = findByToken(token);\n\t\tif (agent == null) {\n\t\t\tagent = new Agent();\n\t\t\tagent.setToken(token);\n\t\t\tagent.setOsName(data.getOsInfo().getOsName());\n\t\t\tagent.setOsVersion(data.getOsInfo().getOsVersion());\n\t\t\tagent.setOsArch(data.getOsInfo().getOsArch());\n\t\t\tagent.setName(data.getName());\n\t\t\tagent.setCpuCount(data.getCpus());\n\t\t\tagent.setIpAddress(data.getIpAddress());","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/service/impl/DefaultAgentService.java#L154-L190","documentation":"When an agent connects, agentConnected validates every attribute name reported in AgentData against AttributeNameValidator.PATTERN (must be alphanumeric/underscore at the ends, only alphanumerics, underscore, dash, space, dot inside) and rejects reserved agent field names separately. Invalid names throw ExplicitException to keep agent metadata keys well-formed.","triggerScenarios":"An agent registers via agentConnected(data, session) with data.getAttributes() containing a key that fails the pattern (e.g. starts with a digit, contains '/', '@', '-', special chars) or equals a reserved Agent.ALL_FIELDS name.","commonSituations":"Custom agent scripts exporting environment-derived attribute keys like 'os.version!' or '123node'; keys with spaces at edges or non-ASCII characters; accidentally using reserved names like 'Name' or 'Version'.","solutions":["Rename the attribute in the agent's data to match the pattern: start/end with alphanumeric or underscore, middle limited to alphanumerics, underscore, dash, space, dot.","Trim leading/trailing spaces from attribute keys before sending.","Replace reserved agent field names with a non-reserved custom key.","Sanitize keys programmatically on the agent side before reporting them to the server."],"exampleFix":"// before\nattributes.put(\"cpu/cores\", \"8\");\n// after\nattributes.put(\"cpu.cores\", \"8\");","handlingStrategy":"validation","validationCode":"const PATTERN = /^[A-Za-z0-9_]([A-Za-z0-9_ .-]*[A-Za-z0-9_])?$/;\nObject.keys(attributes).forEach(k => {\n  if (!PATTERN.test(k)) throw new Error(`Invalid attribute name: ${k}`);\n});","typeGuard":"function isValidAttributeName(k) {\n  return /^[A-Za-z0-9_]([A-Za-z0-9_ .-]*[A-Za-z0-9_])?$/.test(k);\n}","tryCatchPattern":"try {\n  agentNode.connect(data);\n} catch (ExplicitException e) {\n  if (e.getMessage().includes(\"should start and end with alphanumeric\")) {\n    sanitizeAndReconnect();\n  }\n}","preventionTips":["Sanitize environment-derived attribute keys on the agent before sending them.","Trim whitespace from keys and avoid special characters like '/', '@', '!'.","Check Agent.ALL_FIELDS (e.g. Name, Version, Os, Arch) and avoid using them as custom keys.","Add a unit test validating every reported attribute name against the pattern."],"tags":["agent","validation","attribute-names"],"backgroundTag":"invalid-identifier-format","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}