{"record":{"id":"df7406461cb9b5ef","repo":"wavetermdev/waveterm","slug":"invalid-object-reference-q","errorCode":null,"errorMessage":"invalid object reference: %q","messagePattern":"invalid object reference: %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/service/objectservice/objectservice.go","lineNumber":27,"sourceCode":"\t\"strings\"\n\t\"time\"\n\n\t\"github.com/wavetermdev/waveterm/pkg/tsgen/tsgenmeta\"\n\t\"github.com/wavetermdev/waveterm/pkg/waveobj\"\n\t\"github.com/wavetermdev/waveterm/pkg/wcore\"\n\t\"github.com/wavetermdev/waveterm/pkg/wps\"\n\t\"github.com/wavetermdev/waveterm/pkg/wstore\"\n)\n\ntype ObjectService struct{}\n\nconst DefaultTimeout = 2 * time.Second\nconst ConnContextTimeout = 60 * time.Second\n\nfunc parseORef(oref string) (*waveobj.ORef, error) {\n\tfields := strings.Split(oref, \":\")\n\tif len(fields) != 2 {\n\t\treturn nil, fmt.Errorf(\"invalid object reference: %q\", oref)\n\t}\n\treturn &waveobj.ORef{OType: fields[0], OID: fields[1]}, nil\n}\n\nfunc (svc *ObjectService) GetObject_Meta() tsgenmeta.MethodMeta {\n\treturn tsgenmeta.MethodMeta{\n\t\tDesc:     \"get wave object by oref\",\n\t\tArgNames: []string{\"oref\"},\n\t}\n}\n\nfunc (svc *ObjectService) GetObject(orefStr string) (waveobj.WaveObj, error) {\n\toref, err := parseORef(orefStr)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tctx, cancelFn := context.WithTimeout(context.Background(), DefaultTimeout)\n\tdefer cancelFn()","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/service/objectservice/objectservice.go#L9-L45","documentation":"parseORef rejects any string that does not split on ':' into exactly two fields, returning 'invalid object reference: %q'. An ORef must be 'type:oid' (e.g. 'block:xxx'). This is a client-side argument validation error thrown before any DB access, and it propagates through GetObject, GetObjects, and UpdateObjectMeta.","triggerScenarios":"Passing an oref with zero or multiple colons, an empty string, a bare OID without the type prefix, or a full URI with extra ':' segments (e.g. 'wave://block:id').","commonSituations":"Constructing ORefs by hand instead of via waveobj.ORef helpers; storing/logging orefs with added prefixes; copy-pasting identifiers from logs that include scheme prefixes.","solutions":["Ensure the string is exactly 'type:oid' with a single ':' (e.g. 'block:B123')","Strip any scheme/prefix decoration before passing","Build refs programmatically with waveobj.ORef{OType, OID}.String() instead of string concatenation"],"exampleFix":"// before\nobj, err := svc.GetObject(ctx, \"block:B123:extra\")\n// after\nobj, err := svc.GetObject(ctx, (waveobj.ORef{OType: \"block\", OID: \"B123\"}).String())","handlingStrategy":"validation","validationCode":"func validORef(s string) bool {\n    parts := strings.Split(s, \":\")\n    return len(parts) == 2 && parts[0] != \"\" && parts[1] != \"\"\n}\nif !validORef(orefStr) { return fmt.Errorf(\"bad oref %q\", orefStr) }","typeGuard":"func isORef(s string) bool { return len(strings.Split(s, \":\")) == 2 }","tryCatchPattern":"oref, err := parseORef(input)\nif err != nil {\n    return fmt.Errorf(\"bad ref %q: %w\", input, err)\n}","preventionTips":["Always build orefs via ORef.String() helpers, not concatenation","Strip URI schemes/prefixes before passing refs","Keep type prefix and OID ordering consistent ('type:oid')"],"tags":["go","validation","oref","parsing"],"backgroundTag":"invalid-object-reference","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}